Merge remote-tracking branch 'origin/unstable' into merge-to-testing
authorMathieu <mbaudier@argeo.org>
Tue, 6 Dec 2022 05:11:34 +0000 (06:11 +0100)
committerMathieu <mbaudier@argeo.org>
Tue, 6 Dec 2022 05:11:34 +0000 (06:11 +0100)
594 files changed:
Makefile
Makefile-rcp.mk
jni/.cproject [deleted file]
jni/.project [deleted file]
jni/.settings/language.settings.xml [deleted file]
jni/.settings/org.eclipse.cdt.core.prefs [deleted file]
jni/Makefile [deleted file]
jni/jni.mk [deleted file]
jni/org_argeo_api_uuid_libuuid/.gitignore [deleted file]
jni/org_argeo_api_uuid_libuuid/Makefile [deleted file]
jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_DirectLibuuidFactory.c [deleted file]
jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_DirectLibuuidFactory.h [deleted file]
jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_LibuuidFactory.c [deleted file]
jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_LibuuidFactory.h [deleted file]
org.argeo.api.acr/src/org/argeo/api/acr/ArgeoNamespace.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/Content.java
org.argeo.api.acr/src/org/argeo/api/acr/CrAttributeType.java
org.argeo.api.acr/src/org/argeo/api/acr/CrName.java
org.argeo.api.acr/src/org/argeo/api/acr/RuntimeNamespaceContext.java
org.argeo.api.acr/src/org/argeo/api/acr/ldap/Distinguished.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapAcrUtils.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapAttr.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapObj.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/ldap/NamingUtils.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/ldap/NodeOID.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/ldap/SpecifiedName.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/spi/ContentNamespace.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedRepository.java
org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedSession.java
org.argeo.api.acr/src/org/argeo/api/acr/tabular/ArrayTabularRow.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularColumn.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularContent.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularRow.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularRowIterator.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularWriter.java [new file with mode: 0644]
org.argeo.api.acr/src/org/argeo/api/acr/tabular/package-info.java [new file with mode: 0644]
org.argeo.api.cli/src/org/argeo/api/cli/CommandArgsException.java
org.argeo.api.cli/src/org/argeo/api/cli/CommandsCli.java
org.argeo.api.cli/src/org/argeo/api/cli/DescribedCommand.java
org.argeo.api.cli/src/org/argeo/api/cli/HelpCommand.java
org.argeo.api.cli/src/org/argeo/api/cli/PrintHelpRequestException.java [new file with mode: 0644]
org.argeo.api.cms/bnd.bnd
org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsAuthorization.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsDirectory.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsGroup.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsUser.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsUserManager.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/directory/DirectoryDigestUtils.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/directory/HierarchyUnit.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/directory/UserDirectory.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/keyring/CryptoKeyring.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/keyring/Keyring.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/keyring/PBEKeySpecCallback.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/keyring/package-info.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/AbstractWorkingCopy.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/JtaStatusAdapter.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleRollbackException.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleTransaction.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleTransactionManager.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/TransactionStatusAdapter.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/UuidXid.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkContext.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkControl.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkTransaction.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopy.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyProcessor.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyXaResource.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/XAResourceProvider.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/transaction/package-info.java [new file with mode: 0644]
org.argeo.api.register/.classpath [new file with mode: 0644]
org.argeo.api.register/.project [new file with mode: 0644]
org.argeo.api.register/META-INF/.gitignore [new file with mode: 0644]
org.argeo.api.register/bnd.bnd [new file with mode: 0644]
org.argeo.api.register/build.properties [new file with mode: 0644]
org.argeo.api.register/src/org/argeo/api/register/Component.java [new file with mode: 0644]
org.argeo.api.register/src/org/argeo/api/register/ComponentRegister.java [new file with mode: 0644]
org.argeo.api.register/src/org/argeo/api/register/RankingKey.java [new file with mode: 0644]
org.argeo.api.register/src/org/argeo/api/register/SimpleRegister.java [new file with mode: 0644]
org.argeo.api.uuid/src/org/argeo/api/uuid/ConcurrentTimeUuidState.java
org.argeo.api.uuid/src/org/argeo/api/uuid/TimeUuid.java
org.argeo.cms.cli/bnd.bnd
org.argeo.cms.cli/src/org/argeo/cms/cli/ArgeoCli.java
org.argeo.cms.cli/src/org/argeo/cms/cli/CmsCommands.java [new file with mode: 0644]
org.argeo.cms.cli/src/org/argeo/cms/cli/EventCommands.java [new file with mode: 0644]
org.argeo.cms.ee/OSGI-INF/statusHandler.xml
org.argeo.cms.ee/bnd.bnd
org.argeo.cms.ee/src/org/argeo/cms/integration/CmsExceptionsChain.java
org.argeo.cms.ee/src/org/argeo/cms/integration/CmsLogoutServlet.java
org.argeo.cms.ee/src/org/argeo/cms/integration/CmsTokenServlet.java
org.argeo.cms.ee/src/org/argeo/cms/servlet/CmsServletContext.java
org.argeo.cms.ee/src/org/argeo/cms/servlet/ServletHttpResponse.java
org.argeo.cms.ee/src/org/argeo/cms/servlet/ServletUtils.java [new file with mode: 0644]
org.argeo.cms.ee/src/org/argeo/cms/servlet/httpserver/HttpContextServlet.java
org.argeo.cms.ee/src/org/argeo/cms/servlet/httpserver/ServletHttpExchange.java
org.argeo.cms.ee/src/org/argeo/cms/servlet/internal/PkgServlet.java
org.argeo.cms.ee/src/org/argeo/cms/websocket/server/EventEndpoint.java
org.argeo.cms.ee/src/org/argeo/cms/websocket/server/PingEndpoint.java
org.argeo.cms.ee/src/org/argeo/cms/websocket/server/TestEndpoint.java
org.argeo.cms.ee/src/org/argeo/cms/websocket/server/WebSocketHandshakeResponse.java
org.argeo.cms.lib.equinox/.classpath [deleted file]
org.argeo.cms.lib.equinox/.gitignore [deleted file]
org.argeo.cms.lib.equinox/.project [deleted file]
org.argeo.cms.lib.equinox/META-INF/.gitignore [deleted file]
org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml [deleted file]
org.argeo.cms.lib.equinox/bnd.bnd [deleted file]
org.argeo.cms.lib.equinox/build.properties [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java [deleted file]
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/CmsJettyServer.java
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ContextHandlerAttributes.java [new file with mode: 0644]
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ContextHandlerHttpContext.java [new file with mode: 0644]
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/JettyHttpContext.java
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/JettyHttpServer.java
org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ServletHttpContext.java [new file with mode: 0644]
org.argeo.cms.lib.pgsql/.classpath [deleted file]
org.argeo.cms.lib.pgsql/.project [deleted file]
org.argeo.cms.lib.pgsql/bnd.bnd [deleted file]
org.argeo.cms.lib.pgsql/build.properties [deleted file]
org.argeo.cms.lib.pgsql/src/org/argeo/cms/sql/postgres/CheckPg.java [deleted file]
org.argeo.cms.lib.sshd/META-INF/native-image/jni-config.json [deleted file]
org.argeo.cms.lib.sshd/META-INF/native-image/predefined-classes-config.json [deleted file]
org.argeo.cms.lib.sshd/META-INF/native-image/proxy-config.json [deleted file]
org.argeo.cms.lib.sshd/META-INF/native-image/reflect-config.json [deleted file]
org.argeo.cms.lib.sshd/META-INF/native-image/resource-config.json [deleted file]
org.argeo.cms.lib.sshd/META-INF/native-image/serialization-config.json [deleted file]
org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/BasicSshServer.java
org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/SshSync.java
org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/cli/SshCli.java
org.argeo.cms.ux/src/org/argeo/cms/media/SvgToPng.java
org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java
org.argeo.cms.ux/src/org/argeo/cms/ux/acr/ContentHierarchicalPart.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/AbstractColumnsPart.java [new file with mode: 0644]
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/AbstractDataPart.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/AbstractHierarchicalPart.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/AbstractTabularPart.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/CmsDialog.java [new file with mode: 0644]
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/Column.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/ColumnsPart.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/DataPart.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/DataView.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/HierarchicalPart.java
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/TabularPart.java
org.argeo.cms/META-INF/native-image/jni-config.json [deleted file]
org.argeo.cms/META-INF/native-image/predefined-classes-config.json [deleted file]
org.argeo.cms/META-INF/native-image/proxy-config.json [deleted file]
org.argeo.cms/META-INF/native-image/reflect-config.json [deleted file]
org.argeo.cms/META-INF/native-image/resource-config.json [deleted file]
org.argeo.cms/META-INF/native-image/serialization-config.json [deleted file]
org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml
org.argeo.cms/OSGI-INF/cmsContentRepository.xml
org.argeo.cms/OSGI-INF/cmsUserAdmin.xml
org.argeo.cms/OSGI-INF/cmsUserManager.xml
org.argeo.cms/OSGI-INF/transactionManager.xml
org.argeo.cms/src/org/argeo/cms/AbstractKeyring.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/CmsUserManager.java [deleted file]
org.argeo.cms/src/org/argeo/cms/CurrentUser.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/LocaleUtils.java
org.argeo.cms/src/org/argeo/cms/RoleNameUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/SystemRole.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/acr/AbstractContent.java
org.argeo.cms/src/org/argeo/cms/acr/AbstractContentRepository.java
org.argeo.cms/src/org/argeo/cms/acr/CmsContentNamespace.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java
org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java
org.argeo.cms/src/org/argeo/cms/acr/CmsContentTypes.java [deleted file]
org.argeo.cms/src/org/argeo/cms/acr/ContentUtils.java
org.argeo.cms/src/org/argeo/cms/acr/SingleUserContentRepository.java
org.argeo.cms/src/org/argeo/cms/acr/SvgAttrs.java
org.argeo.cms/src/org/argeo/cms/acr/TypesManager.java
org.argeo.cms/src/org/argeo/cms/acr/dav/DavContent.java
org.argeo.cms/src/org/argeo/cms/acr/dav/DavContentProvider.java
org.argeo.cms/src/org/argeo/cms/acr/directory/AbstractDirectoryContent.java
org.argeo.cms/src/org/argeo/cms/acr/directory/DirectoryContent.java
org.argeo.cms/src/org/argeo/cms/acr/directory/DirectoryContentProvider.java
org.argeo.cms/src/org/argeo/cms/acr/directory/HierarchyUnitContent.java
org.argeo.cms/src/org/argeo/cms/acr/directory/RoleContent.java
org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java
org.argeo.cms/src/org/argeo/cms/acr/fs/FsContentProvider.java
org.argeo.cms/src/org/argeo/cms/acr/schemas/XForms-11-Schema.xsd [deleted file]
org.argeo.cms/src/org/argeo/cms/acr/schemas/docbook.xsd [deleted file]
org.argeo.cms/src/org/argeo/cms/acr/schemas/xlink.xsd
org.argeo.cms/src/org/argeo/cms/acr/schemas/xml-events-attribs-1.xsd [deleted file]
org.argeo.cms/src/org/argeo/cms/acr/xml/ElementIterator.java
org.argeo.cms/src/org/argeo/cms/acr/xml/XmlNormalizer.java
org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java
org.argeo.cms/src/org/argeo/cms/auth/CmsRole.java
org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java [deleted file]
org.argeo.cms/src/org/argeo/cms/auth/KeyringLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/RemoteAuthResponse.java
org.argeo.cms/src/org/argeo/cms/auth/RemoteAuthUtils.java
org.argeo.cms/src/org/argeo/cms/auth/RemoteSessionLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/RoleNameUtils.java [deleted file]
org.argeo.cms/src/org/argeo/cms/auth/SingleUserLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/SpnegoLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/SystemRole.java [deleted file]
org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/UserAdminUtils.java
org.argeo.cms/src/org/argeo/cms/client/CmsClient.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/client/SpnegoHttpClient.java [deleted file]
org.argeo.cms/src/org/argeo/cms/client/WebSocketEventClient.java
org.argeo.cms/src/org/argeo/cms/client/WebSocketPing.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/client/WsPing.java [deleted file]
org.argeo.cms/src/org/argeo/cms/client/jaas-client-ipa.cfg
org.argeo.cms/src/org/argeo/cms/dav/DavClient.java
org.argeo.cms/src/org/argeo/cms/dav/DavDepth.java
org.argeo.cms/src/org/argeo/cms/dav/DavHttpHandler.java
org.argeo.cms/src/org/argeo/cms/dav/DavResponse.java
org.argeo.cms/src/org/argeo/cms/dav/MultiStatusReader.java
org.argeo.cms/src/org/argeo/cms/dav/MultiStatusWriter.java
org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectory.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectoryDao.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/AttributesDictionary.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/AuthPassword.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/DefaultLdapEntry.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/IpaUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapConnection.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDao.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDirectoryDao.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapEntry.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapEntryWorkingCopy.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapHierarchyUnit.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapNameUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifDao.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifParser.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifWriter.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/directory/ldap/SharedSecret.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/dns/DnsBrowser.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/dns/SrvRecord.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/file/ChecksumFactory.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/http/HttpHeader.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/http/HttpMethod.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/http/HttpStatus.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/http/server/HttpServerUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java [deleted file]
org.argeo.cms/src/org/argeo/cms/internal/auth/ImpliedByPrincipal.java
org.argeo.cms/src/org/argeo/cms/internal/http/CmsAuthenticator.java
org.argeo.cms/src/org/argeo/cms/internal/http/RemoteAuthHttpExchange.java
org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsActivator.java
org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsOsgiLogger.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsDeploymentImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsEventBusImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserManagerImpl.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/runtime/DeployedContentRepository.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/KernelUtils.java
org.argeo.cms/src/org/argeo/cms/osgi/BundleCmsTheme.java
org.argeo.cms/src/org/argeo/cms/osgi/FilterRequirement.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AggregatingAuthorization.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AggregatingUserAdmin.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AuthenticatingUser.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/DirectoryUserAdmin.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifAuthorization.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifGroup.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifUser.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/OsUserDirectory.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/OsUserUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/TokenUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/jaas-os.cfg [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/osgi/useradmin/package-info.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/runtime/DirectoryConf.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/runtime/StaticCms.java
org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java [deleted file]
org.argeo.cms/src/org/argeo/cms/security/ChecksumFactory.java [deleted file]
org.argeo.cms/src/org/argeo/cms/security/CryptoKeyring.java [deleted file]
org.argeo.cms/src/org/argeo/cms/security/Keyring.java [deleted file]
org.argeo.cms/src/org/argeo/cms/security/PBEKeySpecCallback.java [deleted file]
org.argeo.cms/src/org/argeo/cms/security/package-info.java [deleted file]
org.argeo.cms/src/org/argeo/cms/tabular/ArrayTabularRow.java [deleted file]
org.argeo.cms/src/org/argeo/cms/tabular/TabularColumn.java [deleted file]
org.argeo.cms/src/org/argeo/cms/tabular/TabularContent.java [deleted file]
org.argeo.cms/src/org/argeo/cms/tabular/TabularRow.java [deleted file]
org.argeo.cms/src/org/argeo/cms/tabular/TabularRowIterator.java [deleted file]
org.argeo.cms/src/org/argeo/cms/tabular/TabularWriter.java [deleted file]
org.argeo.cms/src/org/argeo/cms/tabular/package-info.java [deleted file]
org.argeo.cms/src/org/argeo/cms/util/CompositeString.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/CsvParser.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/CsvParserWithLinesAsMap.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/CsvWriter.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/CurrentSubject.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/DictionaryKeys.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/DigestUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/DirH.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/ExceptionsChain.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/FsUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/LangUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/OS.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/PasswordEncryption.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/ServiceChannel.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/StreamUtils.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/Tester.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/TesterStatus.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/Throughput.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/util/package-info.java [new file with mode: 0644]
org.argeo.init/src/org/argeo/init/Service.java
org.argeo.init/src/org/argeo/init/a2/A2Source.java
org.argeo.init/src/org/argeo/init/a2/AbstractProvisioningSource.java
org.argeo.init/src/org/argeo/init/a2/ClasspathSource.java
org.argeo.init/src/org/argeo/init/a2/FsA2Source.java
org.argeo.init/src/org/argeo/init/a2/FsM2Source.java
org.argeo.init/src/org/argeo/init/a2/OsgiContext.java
org.argeo.init/src/org/argeo/init/a2/ProvisioningManager.java
org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java
org.argeo.init/src/org/argeo/init/osgi/log4j.properties [deleted file]
org.argeo.util/.classpath [deleted file]
org.argeo.util/.project [deleted file]
org.argeo.util/META-INF/.gitignore [deleted file]
org.argeo.util/bnd.bnd [deleted file]
org.argeo.util/build.properties [deleted file]
org.argeo.util/src/org/argeo/osgi/internal/EnterpriseActivator.java [deleted file]
org.argeo.util/src/org/argeo/osgi/provisioning/SimpleProvisioningService.java [deleted file]
org.argeo.util/src/org/argeo/osgi/provisioning/package-info.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingAuthorization.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/AuthenticatingUser.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryGroup.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUser.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUserAdmin.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/OsUserUtils.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/TokenUtils.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/jaas-os.cfg [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/package-info.java [deleted file]
org.argeo.util/src/org/argeo/osgi/util/FilterRequirement.java [deleted file]
org.argeo.util/src/org/argeo/osgi/util/OnServiceRegistration.java [deleted file]
org.argeo.util/src/org/argeo/osgi/util/OsgiRegister.java [deleted file]
org.argeo.util/src/org/argeo/util/CompositeString.java [deleted file]
org.argeo.util/src/org/argeo/util/CsvParser.java [deleted file]
org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java [deleted file]
org.argeo.util/src/org/argeo/util/CsvWriter.java [deleted file]
org.argeo.util/src/org/argeo/util/CurrentSubject.java [deleted file]
org.argeo.util/src/org/argeo/util/DictionaryKeys.java [deleted file]
org.argeo.util/src/org/argeo/util/DigestUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/DirH.java [deleted file]
org.argeo.util/src/org/argeo/util/ExceptionsChain.java [deleted file]
org.argeo.util/src/org/argeo/util/FsUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/LangUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/OS.java [deleted file]
org.argeo.util/src/org/argeo/util/PasswordEncryption.java [deleted file]
org.argeo.util/src/org/argeo/util/ServiceChannel.java [deleted file]
org.argeo.util/src/org/argeo/util/StreamUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/Tester.java [deleted file]
org.argeo.util/src/org/argeo/util/TesterStatus.java [deleted file]
org.argeo.util/src/org/argeo/util/Throughput.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/Directory.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/DirectoryConf.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/DirectoryDigestUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/HierarchyUnit.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectoryDao.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/AttributesDictionary.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/AuthPassword.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/DefaultLdapEntry.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/IpaUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdapConnection.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdapDirectoryDao.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdapEntry.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdapEntryWorkingCopy.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdapHierarchyUnit.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdapNameUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdifParser.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/LdifWriter.java [deleted file]
org.argeo.util/src/org/argeo/util/directory/ldap/SharedSecret.java [deleted file]
org.argeo.util/src/org/argeo/util/http/HttpHeader.java [deleted file]
org.argeo.util/src/org/argeo/util/http/HttpMethod.java [deleted file]
org.argeo.util/src/org/argeo/util/http/HttpServerUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/http/HttpStatus.java [deleted file]
org.argeo.util/src/org/argeo/util/internal/DisplayQName.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/Distinguished.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/LdapAttrs.csv [deleted file]
org.argeo.util/src/org/argeo/util/naming/LdapAttrs.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/LdapObjs.csv [deleted file]
org.argeo.util/src/org/argeo/util/naming/LdapObjs.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/NamingUtils.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/NodeOID.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/SpecifiedName.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/dns/DnsBrowser.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/dns/SrvRecord.java [deleted file]
org.argeo.util/src/org/argeo/util/naming/package-info.java [deleted file]
org.argeo.util/src/org/argeo/util/package-info.java [deleted file]
org.argeo.util/src/org/argeo/util/register/Component.java [deleted file]
org.argeo.util/src/org/argeo/util/register/ComponentRegister.java [deleted file]
org.argeo.util/src/org/argeo/util/register/RankingKey.java [deleted file]
org.argeo.util/src/org/argeo/util/register/SimpleRegister.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/AbstractWorkingCopy.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/JtaStatusAdapter.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/SimpleRollbackException.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/SimpleTransaction.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/SimpleTransactionManager.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/TransactionStatusAdapter.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/UuidXid.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/WorkContext.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/WorkControl.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/WorkTransaction.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/WorkingCopy.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/WorkingCopyProcessor.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/WorkingCopyXaResource.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/XAResourceProvider.java [deleted file]
org.argeo.util/src/org/argeo/util/transaction/package-info.java [deleted file]
osgi/equinox/org.argeo.cms.lib.equinox/.classpath [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/.gitignore [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/.project [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/META-INF/.gitignore [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/bnd.bnd [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/build.properties [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java [new file with mode: 0644]
sdk/argeo-build
sdk/branches/unstable.bnd
sdk/cms-e4-rap.properties
sdk/deploy/.gitignore [new file with mode: 0644]
sdk/deploy/argeo-cms-rcp/usr/bin/argeo-desktop-open [new file with mode: 0755]
sdk/deploy/argeo-cms/usr/bin/argeo [new file with mode: 0755]
sdk/deploy/argeo-init/etc/argeo.user.d/jvm.args [new file with mode: 0644]
sdk/deploy/argeo-init/usr/lib/systemd/system/argeo@.service
sdk/deploy/argeo-init/usr/lib/systemd/user/argeo@.service [new file with mode: 0644]
sdk/deploy/argeo-init/usr/share/argeo/jvm.args
swt/org.argeo.cms.e4/META-INF/.gitignore [deleted file]
swt/org.argeo.cms.e4/OSGI-INF/homeRepository.xml [deleted file]
swt/org.argeo.cms.e4/OSGI-INF/userAdminWrapper.xml [deleted file]
swt/org.argeo.cms.e4/bnd.bnd
swt/org.argeo.cms.e4/e4xmi/cms-devops.e4xmi [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/addons/AuthAddon.java
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/files/NodeFsBrowserView.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/files/package-info.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/CloseWorkbench.java
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/BundleNode.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/BundlesView.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/CmsSessionsView.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/ModulesView.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/OsgiConfigurationsView.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/OsgiExplorerImages.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/ServiceReferenceNode.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/StateLabelProvider.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/package-info.java [deleted file]
swt/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/EgoDashboard.java [deleted file]
swt/org.argeo.cms.swt/bnd.bnd
swt/org.argeo.cms.swt/icons/actions/add.png [deleted file]
swt/org.argeo.cms.swt/icons/actions/close-all.png [deleted file]
swt/org.argeo.cms.swt/icons/actions/delete.png [deleted file]
swt/org.argeo.cms.swt/icons/actions/edit.png [deleted file]
swt/org.argeo.cms.swt/icons/actions/save-all.png [deleted file]
swt/org.argeo.cms.swt/icons/actions/save.png [deleted file]
swt/org.argeo.cms.swt/icons/active.gif [deleted file]
swt/org.argeo.cms.swt/icons/add.gif [deleted file]
swt/org.argeo.cms.swt/icons/add.png [deleted file]
swt/org.argeo.cms.swt/icons/addFolder.gif [deleted file]
swt/org.argeo.cms.swt/icons/addPrivileges.gif [deleted file]
swt/org.argeo.cms.swt/icons/addRepo.gif [deleted file]
swt/org.argeo.cms.swt/icons/addWorkspace.png [deleted file]
swt/org.argeo.cms.swt/icons/adminLog.gif [deleted file]
swt/org.argeo.cms.swt/icons/batch.gif [deleted file]
swt/org.argeo.cms.swt/icons/begin.gif [deleted file]
swt/org.argeo.cms.swt/icons/binary.png [deleted file]
swt/org.argeo.cms.swt/icons/browser.gif [deleted file]
swt/org.argeo.cms.swt/icons/bundles.gif [deleted file]
swt/org.argeo.cms.swt/icons/changePassword.gif [deleted file]
swt/org.argeo.cms.swt/icons/clear.gif [deleted file]
swt/org.argeo.cms.swt/icons/close-all.png [deleted file]
swt/org.argeo.cms.swt/icons/commit.gif [deleted file]
swt/org.argeo.cms.swt/icons/delete.png [deleted file]
swt/org.argeo.cms.swt/icons/dumpNode.gif [deleted file]
swt/org.argeo.cms.swt/icons/file.gif [deleted file]
swt/org.argeo.cms.swt/icons/folder.gif [deleted file]
swt/org.argeo.cms.swt/icons/getSize.gif [deleted file]
swt/org.argeo.cms.swt/icons/group.png [deleted file]
swt/org.argeo.cms.swt/icons/home.gif [deleted file]
swt/org.argeo.cms.swt/icons/home.png [deleted file]
swt/org.argeo.cms.swt/icons/import_fs.png [deleted file]
swt/org.argeo.cms.swt/icons/installed.gif [deleted file]
swt/org.argeo.cms.swt/icons/log.gif [deleted file]
swt/org.argeo.cms.swt/icons/logout.png [deleted file]
swt/org.argeo.cms.swt/icons/maintenance.gif [deleted file]
swt/org.argeo.cms.swt/icons/node.gif [deleted file]
swt/org.argeo.cms.swt/icons/nodes.gif [deleted file]
swt/org.argeo.cms.swt/icons/osgi_explorer.gif [deleted file]
swt/org.argeo.cms.swt/icons/password.gif [deleted file]
swt/org.argeo.cms.swt/icons/person-logged-in.png [deleted file]
swt/org.argeo.cms.swt/icons/person.png [deleted file]
swt/org.argeo.cms.swt/icons/query.png [deleted file]
swt/org.argeo.cms.swt/icons/refresh.png [deleted file]
swt/org.argeo.cms.swt/icons/remote_connected.gif [deleted file]
swt/org.argeo.cms.swt/icons/remote_disconnected.gif [deleted file]
swt/org.argeo.cms.swt/icons/remove.gif [deleted file]
swt/org.argeo.cms.swt/icons/removePrivileges.gif [deleted file]
swt/org.argeo.cms.swt/icons/rename.gif [deleted file]
swt/org.argeo.cms.swt/icons/repositories.gif [deleted file]
swt/org.argeo.cms.swt/icons/repository_connected.gif [deleted file]
swt/org.argeo.cms.swt/icons/repository_disconnected.gif [deleted file]
swt/org.argeo.cms.swt/icons/resolved.gif [deleted file]
swt/org.argeo.cms.swt/icons/role.gif [deleted file]
swt/org.argeo.cms.swt/icons/rollback.gif [deleted file]
swt/org.argeo.cms.swt/icons/save-all.png [deleted file]
swt/org.argeo.cms.swt/icons/save.gif [deleted file]
swt/org.argeo.cms.swt/icons/save.png [deleted file]
swt/org.argeo.cms.swt/icons/save_security.png [deleted file]
swt/org.argeo.cms.swt/icons/save_security_disabled.png [deleted file]
swt/org.argeo.cms.swt/icons/security.gif [deleted file]
swt/org.argeo.cms.swt/icons/service_published.gif [deleted file]
swt/org.argeo.cms.swt/icons/service_referenced.gif [deleted file]
swt/org.argeo.cms.swt/icons/sort.gif [deleted file]
swt/org.argeo.cms.swt/icons/starting.gif [deleted file]
swt/org.argeo.cms.swt/icons/sync.gif [deleted file]
swt/org.argeo.cms.swt/icons/user.gif [deleted file]
swt/org.argeo.cms.swt/icons/users.gif [deleted file]
swt/org.argeo.cms.swt/icons/workgroup.png [deleted file]
swt/org.argeo.cms.swt/icons/workgroup.xcf [deleted file]
swt/org.argeo.cms.swt/icons/workspace_connected.png [deleted file]
swt/org.argeo.cms.swt/icons/workspace_disconnected.png [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/cms/jface/dialog/CmsWizardDialog.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/AbstractSwtCmsView.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AbstractPageViewer.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/ContentComposite.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/SwtSection.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/SwtTabbedArea.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/app/AcrContentTreeView.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/auth/DynamicCallbackHandler.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/ChangePasswordDialog.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsFeedback.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/CmsMessageDialog.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/dialogs/LightweightDialog.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/PickUpUserDialog.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UserLP.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UsersImages.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/package-info.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/AbstractSwtView.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtGuidedFormDialog.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtTableView.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtTreeView.java
swt/org.argeo.cms.swt/src/org/argeo/cms/ui/theme/CmsImages.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/cms/ui/theme/package-info.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/ErrorFeedback.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/FeedbackDialog.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/LightweightDialog.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/SingleValue.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/package-info.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/parts/LdifUsersTable.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/parts/package-info.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/util/ViewerUtils.java [deleted file]
swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/util/package-info.java [deleted file]
swt/rap/org.argeo.cms.e4.rap/OSGI-INF/cms-admin-rap.xml [deleted file]
swt/rap/org.argeo.cms.e4.rap/bnd.bnd
swt/rap/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java [deleted file]
swt/rap/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java
swt/rap/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/SimpleRapE4App.java
swt/rap/org.argeo.cms.swt.rap.cli/.classpath [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/.project [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/jni-config.json [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/predefined-classes-config.json [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/proxy-config.json [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/reflect-config.json [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/resource-config.json [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/serialization-config.json [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/bnd.bnd [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/build.properties [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/CmsRapCli.java [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RapJettyServer.java [deleted file]
swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebApp.java
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java
swt/rcp/org.argeo.cms.e4.rcp/argeo-companion.e4xmi
swt/rcp/org.argeo.cms.e4.rcp/bnd.bnd
swt/rcp/org.argeo.cms.e4.rcp/src/org/argeo/cms/e4/rcp/CmsE4Application.java
swt/rcp/org.argeo.cms.swt.rcp.cli/.classpath [deleted file]
swt/rcp/org.argeo.cms.swt.rcp.cli/.project [deleted file]
swt/rcp/org.argeo.cms.swt.rcp.cli/bnd.bnd [deleted file]
swt/rcp/org.argeo.cms.swt.rcp.cli/build.properties [deleted file]
swt/rcp/org.argeo.cms.swt.rcp.cli/src/org/argeo/cms/swt/rcp/cli/CmsCli.java [deleted file]
swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpDisplayFactory.xml
swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpHttpLauncher.xml [new file with mode: 0644]
swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpServletFactory.xml [deleted file]
swt/rcp/org.argeo.cms.swt.rcp/bnd.bnd
swt/rcp/org.argeo.cms.swt.rcp/build.properties
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpDisplayFactory.java
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpHttpLauncher.java [new file with mode: 0644]
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServlet.java [deleted file]
swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServletFactory.java [deleted file]
swt/rcp/org.argeo.swt.specific.rcp/src/org/argeo/eclipse/ui/rcp/internal/rwt/RcpResourceManager.java

index 5d0ce97ce3865568fd59653bacf9e734da1372b1..330bc4fca94bd79b5de123e25dd24079678ad9c7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 include sdk.mk
-.PHONY: clean all osgi jni
+.PHONY: clean all osgi
 
 all: osgi
        $(MAKE) -f Makefile-rcp.mk all
@@ -8,8 +8,8 @@ A2_CATEGORY = org.argeo.cms
 
 BUNDLES = \
 org.argeo.init \
-org.argeo.util \
 org.argeo.api.uuid \
+org.argeo.api.register \
 org.argeo.api.acr \
 org.argeo.api.cli \
 org.argeo.api.cms \
@@ -17,21 +17,19 @@ org.argeo.cms \
 org.argeo.cms.ux \
 org.argeo.cms.ee \
 org.argeo.cms.lib.jetty \
-org.argeo.cms.lib.equinox \
 org.argeo.cms.lib.sshd \
-org.argeo.cms.lib.pgsql \
 org.argeo.cms.cli \
+osgi/equinox/org.argeo.cms.lib.equinox \
 swt/org.argeo.swt.minidesktop \
 swt/org.argeo.cms.swt \
 swt/org.argeo.cms.e4 \
 swt/rap/org.argeo.swt.specific.rap \
 swt/rap/org.argeo.cms.swt.rap \
-swt/rap/org.argeo.cms.swt.rap.cli \
 swt/rap/org.argeo.cms.e4.rap \
 
 DEP_CATEGORIES = \
 org.argeo.tp \
-org.argeo.tp.apache \
+org.argeo.tp.crypto \
 org.argeo.tp.jetty \
 osgi/api/org.argeo.tp.osgi \
 osgi/equinox/org.argeo.tp.eclipse \
@@ -46,28 +44,10 @@ org.argeo.api.uuid \
 org.argeo.api.acr \
 org.argeo.api.cms
 
-jni:
-       $(MAKE) -C jni
-
 clean:
        rm -rf $(BUILD_BASE)
-       $(MAKE) -C jni clean
        $(MAKE) -f Makefile-rcp.mk clean
 
 A2_BUNDLES_CLASSPATH = $(subst $(space),$(pathsep),$(strip $(A2_BUNDLES)))
 
-native-image:
-       mkdir -p $(A2_OUTPUT)/libexec/$(A2_CATEGORY)
-#      cd $(A2_OUTPUT)/libexec/$(A2_CATEGORY) && /opt/graalvm-ce/bin/native-image \
-               -cp $(A2_CLASSPATH):$(A2_BUNDLES_CLASSPATH) org.argeo.eclipse.ui.jetty.CmsRapCli \
-               --enable-url-protocols=http,https \
-               -H:AdditionalSecurityProviders=sun.security.jgss.SunProvider,org.bouncycastle.jce.provider.BouncyCastleProvider,net.i2p.crypto.eddsa.EdDSASecurityProvider \
-               --initialize-at-build-time=org.argeo.init.logging.ThinLogging,org.slf4j.LoggerFactory \
-               --no-fallback 
-       cd $(A2_OUTPUT)/libexec/$(A2_CATEGORY) && /opt/graalvm-ce/bin/native-image \
-               -cp $(A2_CLASSPATH):$(A2_BUNDLES_CLASSPATH) org.argeo.cms.ux.cli.FileSync \
-               --initialize-at-build-time=org.argeo.init.logging.ThinLogging,org.slf4j.LoggerFactory \
-               --no-fallback 
-
-
 include  $(SDK_SRC_BASE)/sdk/argeo-build/osgi.mk
\ No newline at end of file
index 7f1ed9ee21dd6f52ad897bbe0bf23d34d81e2da2..29f1a23a382f3dcabe556338fd56c61f8d68fa67 100644 (file)
@@ -3,35 +3,24 @@ include sdk.mk
 
 all: osgi 
 
-move-rcp: osgi
-       mkdir -p $(A2_OUTPUT)/swt/rcp/$(A2_CATEGORY)
-       mv -v $(A2_OUTPUT)/$(A2_CATEGORY)/*.rcp.$(MAJOR).$(MINOR).jar $(A2_OUTPUT)/swt/rcp/$(A2_CATEGORY)
-       mv -v $(A2_OUTPUT)/$(A2_CATEGORY)/*.rcp.cli.$(MAJOR).$(MINOR).jar $(A2_OUTPUT)/swt/rcp/$(A2_CATEGORY)
-       #touch $(BUILD_BASE)/*.rcp/bnd.bnd
-
 A2_CATEGORY = org.argeo.cms
 
 BUNDLES = \
 swt/rcp/org.argeo.swt.specific.rcp \
 swt/rcp/org.argeo.cms.swt.rcp \
-swt/rcp/org.argeo.cms.swt.rcp.cli \
 swt/rcp/org.argeo.cms.e4.rcp \
 
-A2_OUTPUT = $(SDK_BUILD_BASE)/a2
-A2_BASE = $(A2_OUTPUT)
-
 DEP_CATEGORIES = \
 org.argeo.cms \
 swt/org.argeo.cms \
 org.argeo.tp \
-org.argeo.tp.apache \
+org.argeo.tp.crypto \
 org.argeo.tp.jetty \
 osgi/equinox/org.argeo.tp.eclipse \
 osgi/api/org.argeo.tp.osgi \
 swt/rcp/org.argeo.tp.swt \
 lib/linux/x86_64/swt/rcp/org.argeo.tp.swt \
 swt/rcp/org.argeo.tp.swt.workbench \
-org.argeo.tp.jcr
 
 
 clean:
diff --git a/jni/.cproject b/jni/.cproject
deleted file mode 100644 (file)
index 259cf27..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
-       <storageModule moduleId="org.eclipse.cdt.core.settings">
-               <cconfiguration id="cdt.managedbuild.toolchain.gnu.cross.base.1367283591">
-                       <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.cross.base.1367283591" moduleId="org.eclipse.cdt.core.settings" name="Linux x86_64">
-                               <externalSettings/>
-                               <extensions>
-                                       <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
-                                       <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                               </extensions>
-                       </storageModule>
-                       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
-                               <configuration artifactName="${ProjName}" buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.cross.base.1367283591" name="Linux x86_64" parent="org.eclipse.cdt.build.core.emptycfg">
-                                       <folderInfo id="cdt.managedbuild.toolchain.gnu.cross.base.1367283591.350590933" name="/" resourcePath="">
-                                               <toolChain id="cdt.managedbuild.toolchain.gnu.cross.base.2019979628" name="Cross GCC">
-                                                       <option id="cdt.managedbuild.option.gnu.cross.prefix.715257330" name="Prefix" superClass="cdt.managedbuild.option.gnu.cross.prefix"/>
-                                                       <option id="cdt.managedbuild.option.gnu.cross.path.1210265928" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path"/>
-                                                       <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.2070205849" isAbstract="false" osList="all"/>
-                                                       <builder enableAutoBuild="true" id="cdt.managedbuild.builder.gnu.cross.1468217036" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder"/>
-                                               </toolChain>
-                                       </folderInfo>
-                                       <sourceEntries>
-                                               <entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="org_argeo_api_uuid_libuuid"/>
-                                       </sourceEntries>
-                               </configuration>
-                       </storageModule>
-                       <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
-               </cconfiguration>
-       </storageModule>
-       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
-               <project id="org.argeo.api.uuid.null.1913821562" name="org.argeo.api.uuid"/>
-       </storageModule>
-       <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
-       <storageModule moduleId="refreshScope" versionNumber="2">
-               <configuration configurationName="Linux x86_64"/>
-               <configuration configurationName="Default">
-                       <resource resourceType="PROJECT" workspacePath="/Java_org_argeo_api_uuid"/>
-               </configuration>
-       </storageModule>
-       <storageModule moduleId="scannerConfiguration">
-               <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
-               <scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.cross.base.1367283591;cdt.managedbuild.toolchain.gnu.cross.base.1367283591.350590933;cdt.managedbuild.tool.gnu.cross.c.compiler.453851306;cdt.managedbuild.tool.gnu.c.compiler.input.1102448447">
-                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
-               </scannerConfigBuildInfo>
-               <scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.cross.base.1367283591;cdt.managedbuild.toolchain.gnu.cross.base.1367283591.350590933;cdt.managedbuild.tool.gnu.cross.cpp.compiler.365551368;cdt.managedbuild.tool.gnu.cpp.compiler.input.916135861">
-                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
-               </scannerConfigBuildInfo>
-       </storageModule>
-       <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
-       <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
-               <buildTargets>
-                       <target name="ide" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
-                               <buildCommand>make</buildCommand>
-                               <buildArguments/>
-                               <buildTarget>ide</buildTarget>
-                               <stopOnError>true</stopOnError>
-                               <useDefaultCommand>true</useDefaultCommand>
-                               <runAllBuilders>true</runAllBuilders>
-                       </target>
-               </buildTargets>
-       </storageModule>
-</cproject>
\ No newline at end of file
diff --git a/jni/.project b/jni/.project
deleted file mode 100644 (file)
index 492a807..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>jni-commons</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
-                       <triggers>full,incremental,</triggers>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.cdt.core.cnature</nature>
-               <nature>org.eclipse.cdt.core.ccnature</nature>
-               <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
-               <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
-       </natures>
-</projectDescription>
diff --git a/jni/.settings/language.settings.xml b/jni/.settings/language.settings.xml
deleted file mode 100644 (file)
index e30ee16..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<project>
-       <configuration id="cdt.managedbuild.toolchain.gnu.cross.base.1367283591" name="Linux x86_64">
-               <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
-                       <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
-                       <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
-                       <provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(g?cc)|([gc]\+\+)|(clang)" prefer-non-shared="true"/>
-                       <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
-               </extension>
-       </configuration>
-</project>
\ No newline at end of file
diff --git a/jni/.settings/org.eclipse.cdt.core.prefs b/jni/.settings/org.eclipse.cdt.core.prefs
deleted file mode 100644 (file)
index c8ec5df..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-doxygen/doxygen_new_line_after_brief=true
-doxygen/doxygen_use_brief_tag=false
-doxygen/doxygen_use_javadoc_tags=true
-doxygen/doxygen_use_pre_tag=false
-doxygen/doxygen_use_structural_commands=false
-eclipse.preferences.version=1
diff --git a/jni/Makefile b/jni/Makefile
deleted file mode 100644 (file)
index de2b84c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-include ../sdk.mk
-
-JNIDIRS = org_argeo_api_uuid_libuuid
-
-.PHONY: clean all
-
-all: 
-       $(foreach dir, $(JNIDIRS), $(MAKE) -C $(dir);)
-       
-clean:
-       rm -rf $(BUILD_DIR) $(SDK_BUILD_BASE)/jni
-
-
-
diff --git a/jni/jni.mk b/jni/jni.mk
deleted file mode 100644 (file)
index 40dde44..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-TARGET_EXEC := libJava_$(NATIVE_PACKAGE).so
-
-LDFLAGS = -shared -fPIC -Wl,-soname,$(TARGET_EXEC).$(MAJOR).$(MINOR) $(ADDITIONAL_LIBS)
-CFLAGS = -O3 -fPIC
-
-SRC_DIRS := . 
-
-#
-# Generic Argeo
-#
-BUILD_DIR := $(SDK_BUILD_BASE)/jni/$(NATIVE_PACKAGE)
-
-# Every folder in ./src will need to be passed to GCC so that it can find header files
-INC_DIRS := $(shell find $(SRC_DIRS) -type d) $(JAVA_HOME)/include $(JAVA_HOME)/include/linux $(ADDITIONAL_INCLUDES)
-
-
-.PHONY: clean all ide
-all: $(SDK_BUILD_BASE)/jni/$(TARGET_EXEC)
-
-# Find all the C and C++ files we want to compile
-# Note the single quotes around the * expressions. Make will incorrectly expand these otherwise.
-SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
-
-# String substitution for every C/C++ file.
-# As an example, hello.cpp turns into ./build/hello.cpp.o
-OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
-
-# String substitution (suffix version without %).
-# As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d
-DEPS := $(OBJS:.o=.d)
-
-# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
-INC_FLAGS := $(addprefix -I,$(INC_DIRS))
-
-# The -MMD and -MP flags together generate Makefiles for us!
-# These files will have .d instead of .o as the output.
-CPPFLAGS := $(INC_FLAGS) -MMD -MP
-
-# The final build step.
-$(SDK_BUILD_BASE)/jni/$(TARGET_EXEC): $(OBJS)
-       $(CC) $(OBJS) -o $@ $(LDFLAGS)
-
-# Build step for C source
-$(BUILD_DIR)/%.c.o: %.c
-       mkdir -p $(dir $@)
-       $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
-
-# Build step for C++ source
-$(BUILD_DIR)/%.cpp.o: %.cpp
-       mkdir -p $(dir $@)
-       $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
-
-# Include the .d makefiles. The - at the front suppresses the errors of missing
-# Makefiles. Initially, all the .d files will be missing, and we don't want those
-# errors to show up.
--include $(DEPS)
-
-# MAKEFILE_DIR := $(dir $(firstword $(MAKEFILE_LIST)))
diff --git a/jni/org_argeo_api_uuid_libuuid/.gitignore b/jni/org_argeo_api_uuid_libuuid/.gitignore
deleted file mode 100644 (file)
index 84c048a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/build/
diff --git a/jni/org_argeo_api_uuid_libuuid/Makefile b/jni/org_argeo_api_uuid_libuuid/Makefile
deleted file mode 100644 (file)
index cfeb1db..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-NATIVE_PACKAGE := org_argeo_api_uuid_libuuid
-
-ADDITIONAL_INCLUDES = /usr/include/uuid
-ADDITIONAL_LIBS = -luuid
-
-include ../../sdk.mk
-include ../jni.mk
-
diff --git a/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_DirectLibuuidFactory.c b/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_DirectLibuuidFactory.c
deleted file mode 100644 (file)
index a5aeed0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <jni.h>
-#include <uuid.h>
-#include "org_argeo_api_uuid_libuuid_DirectLibuuidFactory.h"
-
-JNIEXPORT void JNICALL Java_org_argeo_api_uuid_libuuid_DirectLibuuidFactory_timeUUID(
-               JNIEnv *env, jobject uuidFactory, jobject uuidBuf) {
-       uuid_generate_time((*env)->GetDirectBufferAddress(env, uuidBuf));
-}
diff --git a/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_DirectLibuuidFactory.h b/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_DirectLibuuidFactory.h
deleted file mode 100644 (file)
index 5f18bf7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class org_argeo_api_uuid_libuuid_DirectLibuuidFactory */
-
-#ifndef _Included_org_argeo_api_uuid_libuuid_DirectLibuuidFactory
-#define _Included_org_argeo_api_uuid_libuuid_DirectLibuuidFactory
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class:     org_argeo_api_uuid_libuuid_DirectLibuuidFactory
- * Method:    timeUUID
- * Signature: (Ljava/nio/ByteBuffer;)V
- */
-JNIEXPORT void JNICALL Java_org_argeo_api_uuid_libuuid_DirectLibuuidFactory_timeUUID
-  (JNIEnv *, jobject, jobject);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_LibuuidFactory.c b/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_LibuuidFactory.c
deleted file mode 100644 (file)
index f97b1f4..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <jni.h>
-#include <uuid.h>
-#include "org_argeo_api_uuid_libuuid_LibuuidFactory.h"
-
-/*
- * UTILITIES
- */
-
-static inline jobject fromBytes(JNIEnv *env, uuid_t out) {
-       jlong msb = 0;
-       jlong lsb = 0;
-
-       for (int i = 0; i < 8; i++)
-               msb = (msb << 8) | (out[i] & 0xff);
-       for (int i = 8; i < 16; i++)
-               lsb = (lsb << 8) | (out[i] & 0xff);
-
-       jclass uuidClass = (*env)->FindClass(env, "java/util/UUID");
-       jmethodID uuidConstructor = (*env)->GetMethodID(env, uuidClass, "<init>",
-                       "(JJ)V");
-
-       jobject jUUID = (*env)->AllocObject(env, uuidClass);
-       (*env)->CallVoidMethod(env, jUUID, uuidConstructor, msb, lsb);
-
-       return jUUID;
-}
-
-static inline void toBytes(JNIEnv *env, jobject jUUID, uuid_t result) {
-
-       jclass uuidClass = (*env)->FindClass(env, "java/util/UUID");
-       jmethodID getMostSignificantBits = (*env)->GetMethodID(env, uuidClass,
-                       "getMostSignificantBits", "()J");
-       jmethodID getLeastSignificantBits = (*env)->GetMethodID(env, uuidClass,
-                       "getLeastSignificantBits", "()J");
-
-       jlong msb = (*env)->CallLongMethod(env, jUUID, getMostSignificantBits);
-       jlong lsb = (*env)->CallLongMethod(env, jUUID, getLeastSignificantBits);
-
-       for (int i = 0; i < 8; i++)
-               result[i] = (unsigned char) ((msb >> ((7 - i) * 8)) & 0xff);
-       for (int i = 8; i < 16; i++)
-               result[i] = (unsigned char) ((lsb >> ((15 - i) * 8)) & 0xff);
-}
-
-/*
- * JNI IMPLEMENTATION
- */
-
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_timeUUID(
-               JNIEnv *env, jobject uuidFactory) {
-       uuid_t out;
-
-       uuid_generate_time(out);
-       return fromBytes(env, out);
-}
-
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_nameUUIDv5(
-               JNIEnv *env, jobject uuidFactory, jobject namespaceUuid,
-               jbyteArray name) {
-       uuid_t ns;
-       uuid_t out;
-
-       toBytes(env, namespaceUuid, ns);
-       jsize length = (*env)->GetArrayLength(env, name);
-       jbyte *bytes = (*env)->GetByteArrayElements(env, name, 0);
-
-       uuid_generate_sha1(out, ns, bytes, length);
-       return fromBytes(env, out);
-}
-
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_nameUUIDv3(
-               JNIEnv *env, jobject uuidFactory, jobject namespaceUuid,
-               jbyteArray name) {
-       uuid_t ns;
-       uuid_t out;
-
-       toBytes(env, namespaceUuid, ns);
-       jsize length = (*env)->GetArrayLength(env, name);
-       jbyte *bytes = (*env)->GetByteArrayElements(env, name, 0);
-
-       uuid_generate_md5(out, ns, bytes, length);
-       return fromBytes(env, out);
-}
-
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_randomUUIDStrong(
-               JNIEnv *env, jobject uuidFactory) {
-       uuid_t out;
-
-       uuid_generate_random(out);
-       return fromBytes(env, out);
-}
diff --git a/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_LibuuidFactory.h b/jni/org_argeo_api_uuid_libuuid/org_argeo_api_uuid_libuuid_LibuuidFactory.h
deleted file mode 100644 (file)
index ad0ac5e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class org_argeo_api_uuid_libuuid_LibuuidFactory */
-
-#ifndef _Included_org_argeo_api_uuid_libuuid_LibuuidFactory
-#define _Included_org_argeo_api_uuid_libuuid_LibuuidFactory
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class:     org_argeo_api_uuid_libuuid_LibuuidFactory
- * Method:    timeUUID
- * Signature: ()Ljava/util/UUID;
- */
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_timeUUID
-  (JNIEnv *, jobject);
-
-/*
- * Class:     org_argeo_api_uuid_libuuid_LibuuidFactory
- * Method:    nameUUIDv5
- * Signature: (Ljava/util/UUID;[B)Ljava/util/UUID;
- */
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_nameUUIDv5
-  (JNIEnv *, jobject, jobject, jbyteArray);
-
-/*
- * Class:     org_argeo_api_uuid_libuuid_LibuuidFactory
- * Method:    nameUUIDv3
- * Signature: (Ljava/util/UUID;[B)Ljava/util/UUID;
- */
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_nameUUIDv3
-  (JNIEnv *, jobject, jobject, jbyteArray);
-
-/*
- * Class:     org_argeo_api_uuid_libuuid_LibuuidFactory
- * Method:    randomUUIDStrong
- * Signature: ()Ljava/util/UUID;
- */
-JNIEXPORT jobject JNICALL Java_org_argeo_api_uuid_libuuid_LibuuidFactory_randomUUIDStrong
-  (JNIEnv *, jobject);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ArgeoNamespace.java b/org.argeo.api.acr/src/org/argeo/api/acr/ArgeoNamespace.java
new file mode 100644 (file)
index 0000000..98131d1
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.api.acr;
+
+/** Namespaces declared by Argeo. */
+public enum ArgeoNamespace {
+       ;
+
+       public final static String CR_NAMESPACE_URI = "http://www.argeo.org/ns/cr";
+       public final static String CR_DEFAULT_PREFIX = "cr";
+       public final static String LDAP_NAMESPACE_URI = "http://www.argeo.org/ns/ldap";
+       public final static String LDAP_DEFAULT_PREFIX = "ldap";
+       public final static String ROLE_NAMESPACE_URI = "http://www.argeo.org/ns/role";
+       public final static String ROLE_DEFAULT_PREFIX = "role";
+
+}
index b605fa1e0062140b18fd5b1784fe8ea0fd6171bc..f52ab31b8f25223e109b4781707502f924cd5ebd 100644 (file)
@@ -128,6 +128,14 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                return true;
        }
 
+       /** AND */
+       default boolean isContentClass(QNamed... contentClass) {
+               List<QName> lst = new ArrayList<>();
+               for (QNamed qNamed : contentClass)
+                       lst.add(qNamed.qName());
+               return isContentClass(lst.toArray(new QName[lst.size()]));
+       }
+
        /** OR */
        default boolean hasContentClass(QName... contentClass) {
                List<QName> contentClasses = getContentClasses();
@@ -138,8 +146,12 @@ public interface Content extends Iterable<Content>, Map<QName, Object> {
                return false;
        }
 
-       default boolean hasContentClass(QNamed contentClass) {
-               return hasContentClass(contentClass.qName());
+       /** OR */
+       default boolean hasContentClass(QNamed... contentClass) {
+               List<QName> lst = new ArrayList<>();
+               for (QNamed qNamed : contentClass)
+                       lst.add(qNamed.qName());
+               return hasContentClass(lst.toArray(new QName[lst.size()]));
        }
 
        /*
index 55ad079ec16b1927c8bc214c877a000d0f281ef7..3e12fb1c87067fd188bfa34cac4c44794c9ec5d2 100644 (file)
@@ -28,7 +28,7 @@ public enum CrAttributeType {
        // we do not support short and float, like recent additions to Java
        // (e.g. optional primitives)
        DATE_TIME(Instant.class, W3C_XML_SCHEMA_NS_URI, "dateTime", new InstantFormatter()), //
-       UUID(UUID.class, CrName.CR_NAMESPACE_URI, "uuid", new UuidFormatter()), //
+       UUID(UUID.class, ArgeoNamespace.CR_NAMESPACE_URI, "uuid", new UuidFormatter()), //
        ANY_URI(URI.class, W3C_XML_SCHEMA_NS_URI, "anyUri", new UriFormatter()), //
        STRING(String.class, W3C_XML_SCHEMA_NS_URI, "string", new StringFormatter()), //
        ;
index f618335077eadbcd093273cb584ed1d9520449fc..ead47377bddff3eb5cd26d179636735d3f578bdc 100644 (file)
@@ -34,14 +34,7 @@ public enum CrName implements QNamed {
        //
        ;
 
-       public final static String CR_NAMESPACE_URI = "http://www.argeo.org/ns/cr";
-       public final static String CR_DEFAULT_PREFIX = "cr";
-
-       public final static String LDAP_NAMESPACE_URI = "http://www.argeo.org/ns/ldap";
-       public final static String LDAP_DEFAULT_PREFIX = "ldap";
-
-       public final static String ROLE_NAMESPACE_URI = "http://www.argeo.org/ns/role";
-       public final static String ROLE_DEFAULT_PREFIX = "role";
+       
 
 //     private final ContentName value;
 
@@ -55,12 +48,12 @@ public enum CrName implements QNamed {
 
        @Override
        public String getNamespace() {
-               return CR_NAMESPACE_URI;
+               return ArgeoNamespace.CR_NAMESPACE_URI;
        }
 
        @Override
        public String getDefaultPrefix() {
-               return CR_DEFAULT_PREFIX;
+               return ArgeoNamespace.CR_DEFAULT_PREFIX;
        }
 
 }
index 0941597d749b7887f7dc4227e76e71acd211979c..1c55156ee352b389c387c56f2ea30103dae2371c 100644 (file)
@@ -61,9 +61,9 @@ public class RuntimeNamespaceContext implements NamespaceContext {
                register(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, XSD_INSTANCE_DEFAULT_PREFIX);
 
                // Argeo specific
-               register(CrName.CR_NAMESPACE_URI, CrName.CR_DEFAULT_PREFIX);
-               register(CrName.LDAP_NAMESPACE_URI, CrName.LDAP_DEFAULT_PREFIX);
-               register(CrName.ROLE_NAMESPACE_URI, CrName.ROLE_DEFAULT_PREFIX);
+               register(ArgeoNamespace.CR_NAMESPACE_URI, ArgeoNamespace.CR_DEFAULT_PREFIX);
+               register(ArgeoNamespace.LDAP_NAMESPACE_URI, ArgeoNamespace.LDAP_DEFAULT_PREFIX);
+               register(ArgeoNamespace.ROLE_NAMESPACE_URI, ArgeoNamespace.ROLE_DEFAULT_PREFIX);
        }
 
        public static NamespaceContext getNamespaceContext() {
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/Distinguished.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/Distinguished.java
new file mode 100644 (file)
index 0000000..52556cf
--- /dev/null
@@ -0,0 +1,36 @@
+package org.argeo.api.acr.ldap;
+
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+/**
+ * An object that can be identified with an X.500 distinguished name.
+ * 
+ * @see "https://tools.ietf.org/html/rfc1779"
+ */
+public interface Distinguished {
+       /** The related distinguished name. */
+       String dn();
+
+       /** The related distinguished name as an {@link LdapName}. */
+       default LdapName distinguishedName() {
+               try {
+                       return new LdapName(dn());
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Distinguished name " + dn() + " is not properly formatted.", e);
+               }
+       }
+
+       /** List all DNs of an enumeration as strings. */
+       static Set<String> enumToDns(EnumSet<? extends Distinguished> enumSet) {
+               Set<String> res = new TreeSet<>();
+               for (Enum<? extends Distinguished> enm : enumSet) {
+                       res.add(((Distinguished) enm).dn());
+               }
+               return res;
+       }
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapAcrUtils.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapAcrUtils.java
new file mode 100644 (file)
index 0000000..7ef64c2
--- /dev/null
@@ -0,0 +1,31 @@
+package org.argeo.api.acr.ldap;
+
+import java.util.Locale;
+
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentName;
+
+/** Utilities around ACR and LDAP conventions. */
+public class LdapAcrUtils {
+
+       /** singleton */
+       private LdapAcrUtils() {
+       }
+
+       public static Object getLocalized(Content content, QName key, Locale locale) {
+               if (locale == null)
+                       throw new IllegalArgumentException("A locale must be specified");
+               Object value = null;
+               if (locale.getCountry() != null && !locale.getCountry().equals(""))
+                       value = content.get(new ContentName(key.getNamespaceURI(),
+                                       key.getLocalPart() + ";lang-" + locale.getLanguage() + "-" + locale.getCountry()));
+               if (value == null)
+                       value = content
+                                       .get(new ContentName(key.getNamespaceURI(), key.getLocalPart() + ";lang-" + locale.getLanguage()));
+               if (value == null)
+                       value = content.get(key);
+               return value;
+       }
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapAttr.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapAttr.java
new file mode 100644 (file)
index 0000000..81b36ec
--- /dev/null
@@ -0,0 +1,368 @@
+package org.argeo.api.acr.ldap;
+
+import static org.argeo.api.acr.ArgeoNamespace.LDAP_DEFAULT_PREFIX;
+import static org.argeo.api.acr.ArgeoNamespace.LDAP_NAMESPACE_URI;
+
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.ContentName;
+import org.argeo.api.acr.QNamed;
+import org.argeo.api.acr.RuntimeNamespaceContext;
+
+/**
+ * Standard LDAP attributes as per:<br>
+ * - <a href= "https://www.ldap.com/ldap-oid-reference">Standard LDAP</a><br>
+ * - <a href=
+ * "https://github.com/krb5/krb5/blob/master/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema">Kerberos
+ * LDAP (partial)</a>
+ */
+public enum LdapAttr implements QNamed, SpecifiedName {
+       /** */
+       uid("0.9.2342.19200300.100.1.1", "RFC 4519"),
+       /** */
+       mail("0.9.2342.19200300.100.1.3", "RFC 4524"),
+       /** */
+       info("0.9.2342.19200300.100.1.4", "RFC 4524"),
+       /** */
+       drink("0.9.2342.19200300.100.1.5", "RFC 4524"),
+       /** */
+       roomNumber("0.9.2342.19200300.100.1.6", "RFC 4524"),
+       /** */
+       photo("0.9.2342.19200300.100.1.7", "RFC 2798"),
+       /** */
+       userClass("0.9.2342.19200300.100.1.8", "RFC 4524"),
+       /** */
+       host("0.9.2342.19200300.100.1.9", "RFC 4524"),
+       /** */
+       manager("0.9.2342.19200300.100.1.10", "RFC 4524"),
+       /** */
+       documentIdentifier("0.9.2342.19200300.100.1.11", "RFC 4524"),
+       /** */
+       documentTitle("0.9.2342.19200300.100.1.12", "RFC 4524"),
+       /** */
+       documentVersion("0.9.2342.19200300.100.1.13", "RFC 4524"),
+       /** */
+       documentAuthor("0.9.2342.19200300.100.1.14", "RFC 4524"),
+       /** */
+       documentLocation("0.9.2342.19200300.100.1.15", "RFC 4524"),
+       /** */
+       homePhone("0.9.2342.19200300.100.1.20", "RFC 4524"),
+       /** */
+       secretary("0.9.2342.19200300.100.1.21", "RFC 4524"),
+       /** */
+       dc("0.9.2342.19200300.100.1.25", "RFC 4519"),
+       /** */
+       associatedDomain("0.9.2342.19200300.100.1.37", "RFC 4524"),
+       /** */
+       associatedName("0.9.2342.19200300.100.1.38", "RFC 4524"),
+       /** */
+       homePostalAddress("0.9.2342.19200300.100.1.39", "RFC 4524"),
+       /** */
+       personalTitle("0.9.2342.19200300.100.1.40", "RFC 4524"),
+       /** */
+       mobile("0.9.2342.19200300.100.1.41", "RFC 4524"),
+       /** */
+       pager("0.9.2342.19200300.100.1.42", "RFC 4524"),
+       /** */
+       co("0.9.2342.19200300.100.1.43", "RFC 4524"),
+       /** */
+       uniqueIdentifier("0.9.2342.19200300.100.1.44", "RFC 4524"),
+       /** */
+       organizationalStatus("0.9.2342.19200300.100.1.45", "RFC 4524"),
+       /** */
+       buildingName("0.9.2342.19200300.100.1.48", "RFC 4524"),
+       /** */
+       audio("0.9.2342.19200300.100.1.55", "RFC 2798"),
+       /** */
+       documentPublisher("0.9.2342.19200300.100.1.56", "RFC 4524"),
+       /** */
+       jpegPhoto("0.9.2342.19200300.100.1.60", "RFC 2798"),
+       /** */
+       vendorName("1.3.6.1.1.4", "RFC 3045"),
+       /** */
+       vendorVersion("1.3.6.1.1.5", "RFC 3045"),
+       /** */
+       entryUUID("1.3.6.1.1.16.4", "RFC 4530"),
+       /** */
+       entryDN("1.3.6.1.1.20", "RFC 5020"),
+       /** */
+       labeledURI("1.3.6.1.4.1.250.1.57", "RFC 2798"),
+       /** */
+       numSubordinates("1.3.6.1.4.1.453.16.2.103", "draft-ietf-boreham-numsubordinates"),
+       /** */
+       namingContexts("1.3.6.1.4.1.1466.101.120.5", "RFC 4512"),
+       /** */
+       altServer("1.3.6.1.4.1.1466.101.120.6", "RFC 4512"),
+       /** */
+       supportedExtension("1.3.6.1.4.1.1466.101.120.7", "RFC 4512"),
+       /** */
+       supportedControl("1.3.6.1.4.1.1466.101.120.13", "RFC 4512"),
+       /** */
+       supportedSASLMechanisms("1.3.6.1.4.1.1466.101.120.14", "RFC 4512"),
+       /** */
+       supportedLDAPVersion("1.3.6.1.4.1.1466.101.120.15", "RFC 4512"),
+       /** */
+       ldapSyntaxes("1.3.6.1.4.1.1466.101.120.16", "RFC 4512"),
+       /** */
+       supportedAuthPasswordSchemes("1.3.6.1.4.1.4203.1.3.3", "RFC 3112"),
+       /** */
+       authPassword("1.3.6.1.4.1.4203.1.3.4", "RFC 3112"),
+       /** */
+       supportedFeatures("1.3.6.1.4.1.4203.1.3.5", "RFC 4512"),
+       /** */
+       inheritable("1.3.6.1.4.1.7628.5.4.1", "draft-ietf-ldup-subentry"),
+       /** */
+       blockInheritance("1.3.6.1.4.1.7628.5.4.2", "draft-ietf-ldup-subentry"),
+       /** */
+       objectClass("2.5.4.0", "RFC 4512"),
+       /** */
+       aliasedObjectName("2.5.4.1", "RFC 4512"),
+       /** */
+       cn("2.5.4.3", "RFC 4519"),
+       /** */
+       sn("2.5.4.4", "RFC 4519"),
+       /** */
+       serialNumber("2.5.4.5", "RFC 4519"),
+       /** */
+       c("2.5.4.6", "RFC 4519"),
+       /** */
+       l("2.5.4.7", "RFC 4519"),
+       /** */
+       st("2.5.4.8", "RFC 4519"),
+       /** */
+       street("2.5.4.9", "RFC 4519"),
+       /** */
+       o("2.5.4.10", "RFC 4519"),
+       /** */
+       ou("2.5.4.11", "RFC 4519"),
+       /** */
+       title("2.5.4.12", "RFC 4519"),
+       /** */
+       description("2.5.4.13", "RFC 4519"),
+       /** */
+       searchGuide("2.5.4.14", "RFC 4519"),
+       /** */
+       businessCategory("2.5.4.15", "RFC 4519"),
+       /** */
+       postalAddress("2.5.4.16", "RFC 4519"),
+       /** */
+       postalCode("2.5.4.17", "RFC 4519"),
+       /** */
+       postOfficeBox("2.5.4.18", "RFC 4519"),
+       /** */
+       physicalDeliveryOfficeName("2.5.4.19", "RFC 4519"),
+       /** */
+       telephoneNumber("2.5.4.20", "RFC 4519"),
+       /** */
+       telexNumber("2.5.4.21", "RFC 4519"),
+       /** */
+       teletexTerminalIdentifier("2.5.4.22", "RFC 4519"),
+       /** */
+       facsimileTelephoneNumber("2.5.4.23", "RFC 4519"),
+       /** */
+       x121Address("2.5.4.24", "RFC 4519"),
+       /** */
+       internationalISDNNumber("2.5.4.25", "RFC 4519"),
+       /** */
+       registeredAddress("2.5.4.26", "RFC 4519"),
+       /** */
+       destinationIndicator("2.5.4.27", "RFC 4519"),
+       /** */
+       preferredDeliveryMethod("2.5.4.28", "RFC 4519"),
+       /** */
+       member("2.5.4.31", "RFC 4519"),
+       /** */
+       owner("2.5.4.32", "RFC 4519"),
+       /** */
+       roleOccupant("2.5.4.33", "RFC 4519"),
+       /** */
+       seeAlso("2.5.4.34", "RFC 4519"),
+       /** */
+       userPassword("2.5.4.35", "RFC 4519"),
+       /** */
+       userCertificate("2.5.4.36", "RFC 4523"),
+       /** */
+       cACertificate("2.5.4.37", "RFC 4523"),
+       /** */
+       authorityRevocationList("2.5.4.38", "RFC 4523"),
+       /** */
+       certificateRevocationList("2.5.4.39", "RFC 4523"),
+       /** */
+       crossCertificatePair("2.5.4.40", "RFC 4523"),
+       /** */
+       name("2.5.4.41", "RFC 4519"),
+       /** */
+       givenName("2.5.4.42", "RFC 4519"),
+       /** */
+       initials("2.5.4.43", "RFC 4519"),
+       /** */
+       generationQualifier("2.5.4.44", "RFC 4519"),
+       /** */
+       x500UniqueIdentifier("2.5.4.45", "RFC 4519"),
+       /** */
+       dnQualifier("2.5.4.46", "RFC 4519"),
+       /** */
+       enhancedSearchGuide("2.5.4.47", "RFC 4519"),
+       /** */
+       distinguishedName("2.5.4.49", "RFC 4519"),
+       /** */
+       uniqueMember("2.5.4.50", "RFC 4519"),
+       /** */
+       houseIdentifier("2.5.4.51", "RFC 4519"),
+       /** */
+       supportedAlgorithms("2.5.4.52", "RFC 4523"),
+       /** */
+       deltaRevocationList("2.5.4.53", "RFC 4523"),
+       /** */
+       createTimestamp("2.5.18.1", "RFC 4512"),
+       /** */
+       modifyTimestamp("2.5.18.2", "RFC 4512"),
+       /** */
+       creatorsName("2.5.18.3", "RFC 4512"),
+       /** */
+       modifiersName("2.5.18.4", "RFC 4512"),
+       /** */
+       subschemaSubentry("2.5.18.10", "RFC 4512"),
+       /** */
+       dITStructureRules("2.5.21.1", "RFC 4512"),
+       /** */
+       dITContentRules("2.5.21.2", "RFC 4512"),
+       /** */
+       matchingRules("2.5.21.4", "RFC 4512"),
+       /** */
+       attributeTypes("2.5.21.5", "RFC 4512"),
+       /** */
+       objectClasses("2.5.21.6", "RFC 4512"),
+       /** */
+       nameForms("2.5.21.7", "RFC 4512"),
+       /** */
+       matchingRuleUse("2.5.21.8", "RFC 4512"),
+       /** */
+       structuralObjectClass("2.5.21.9", "RFC 4512"),
+       /** */
+       governingStructureRule("2.5.21.10", "RFC 4512"),
+       /** */
+       carLicense("2.16.840.1.113730.3.1.1", "RFC 2798"),
+       /** */
+       departmentNumber("2.16.840.1.113730.3.1.2", "RFC 2798"),
+       /** */
+       employeeNumber("2.16.840.1.113730.3.1.3", "RFC 2798"),
+       /** */
+       employeeType("2.16.840.1.113730.3.1.4", "RFC 2798"),
+       /** */
+       changeNumber("2.16.840.1.113730.3.1.5", "draft-good-ldap-changelog"),
+       /** */
+       targetDN("2.16.840.1.113730.3.1.6", "draft-good-ldap-changelog"),
+       /** */
+       changeType("2.16.840.1.113730.3.1.7", "draft-good-ldap-changelog"),
+       /** */
+       changes("2.16.840.1.113730.3.1.8", "draft-good-ldap-changelog"),
+       /** */
+       newRDN("2.16.840.1.113730.3.1.9", "draft-good-ldap-changelog"),
+       /** */
+       deleteOldRDN("2.16.840.1.113730.3.1.10", "draft-good-ldap-changelog"),
+       /** */
+       newSuperior("2.16.840.1.113730.3.1.11", "draft-good-ldap-changelog"),
+       /** */
+       ref("2.16.840.1.113730.3.1.34", "RFC 3296"),
+       /** */
+       changelog("2.16.840.1.113730.3.1.35", "draft-good-ldap-changelog"),
+       /** */
+       preferredLanguage("2.16.840.1.113730.3.1.39", "RFC 2798"),
+       /** */
+       userSMIMECertificate("2.16.840.1.113730.3.1.40", "RFC 2798"),
+       /** */
+       userPKCS12("2.16.840.1.113730.3.1.216", "RFC 2798"),
+       /** */
+       displayName("2.16.840.1.113730.3.1.241", "RFC 2798"),
+
+       // Sun memberOf
+       memberOf("1.2.840.113556.1.2.102", "389 DS memberOf"),
+
+       // KERBEROS (partial)
+       krbPrincipalName("2.16.840.1.113719.1.301.6.8.1", "Novell Kerberos Schema Definitions"),
+
+       // RFC 2985 and RFC 3039 (partial)
+       dateOfBirth("1.3.6.1.5.5.7.9.1", "RFC 2985"),
+       /** */
+       placeOfBirth("1.3.6.1.5.5.7.9.2", "RFC 2985"),
+       /** */
+       gender("1.3.6.1.5.5.7.9.3", "RFC 2985"),
+       /** */
+       countryOfCitizenship("1.3.6.1.5.5.7.9.4", "RFC 2985"),
+       /** */
+       countryOfResidence("1.3.6.1.5.5.7.9.5", "RFC 2985"),
+
+       // RFC 2307bis (partial)
+       /** */
+       uidNumber("1.3.6.1.1.1.1.0", "RFC 2307bis"),
+       /** */
+       gidNumber("1.3.6.1.1.1.1.1", "RFC 2307bis"),
+       /** */
+       homeDirectory("1.3.6.1.1.1.1.3", "RFC 2307bis"),
+       /** */
+       loginShell("1.3.6.1.1.1.1.4", "RFC 2307bis"),
+       /** */
+       memberUid("1.3.6.1.1.1.1.12", "RFC 2307bis"),
+
+       //
+       ;
+
+       public final static String DN = "dn";
+
+       private final String oid, spec;
+       private final QName value;
+
+       LdapAttr(String oid, String spec) {
+               this.oid = oid;
+               this.spec = spec;
+               this.value = new ContentName(LDAP_NAMESPACE_URI, name());
+       }
+
+       public QName qName() {
+               return value;
+       }
+
+       @Override
+       public String getID() {
+               return oid;
+       }
+
+       @Override
+       public String getSpec() {
+               return spec;
+       }
+
+       @Deprecated
+       public String property() {
+               return get();
+       }
+
+       @Deprecated
+       public String qualified() {
+               return get();
+       }
+
+       /** #deprecated use {@link #qName()} instead. */
+//     @Deprecated
+       public String get() {
+               return RuntimeNamespaceContext.getNamespaceContext().getPrefix(LDAP_NAMESPACE_URI) + ":" + name();
+       }
+
+       @Override
+       public final String toString() {
+               // must return the name
+               return name();
+       }
+
+       @Override
+       public String getNamespace() {
+               return LDAP_NAMESPACE_URI;
+       }
+
+       @Override
+       public String getDefaultPrefix() {
+               return LDAP_DEFAULT_PREFIX;
+       }
+
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapObj.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapObj.java
new file mode 100644 (file)
index 0000000..061d117
--- /dev/null
@@ -0,0 +1,155 @@
+package org.argeo.api.acr.ldap;
+
+import static org.argeo.api.acr.ArgeoNamespace.LDAP_DEFAULT_PREFIX;
+import static org.argeo.api.acr.ArgeoNamespace.LDAP_NAMESPACE_URI;
+
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.ArgeoNamespace;
+import org.argeo.api.acr.ContentName;
+import org.argeo.api.acr.QNamed;
+import org.argeo.api.acr.RuntimeNamespaceContext;
+
+/**
+ * Standard LDAP object classes as per
+ * <a href="https://www.ldap.com/ldap-oid-reference">https://www.ldap.com/ldap-
+ * oid-reference</a>
+ */
+public enum LdapObj implements QNamed, SpecifiedName {
+       account("0.9.2342.19200300.100.4.5", "RFC 4524"),
+       /** */
+       document("0.9.2342.19200300.100.4.6", "RFC 4524"),
+       /** */
+       room("0.9.2342.19200300.100.4.7", "RFC 4524"),
+       /** */
+       documentSeries("0.9.2342.19200300.100.4.9", "RFC 4524"),
+       /** */
+       domain("0.9.2342.19200300.100.4.13", "RFC 4524"),
+       /** */
+       rFC822localPart("0.9.2342.19200300.100.4.14", "RFC 4524"),
+       /** */
+       domainRelatedObject("0.9.2342.19200300.100.4.17", "RFC 4524"),
+       /** */
+       friendlyCountry("0.9.2342.19200300.100.4.18", "RFC 4524"),
+       /** */
+       simpleSecurityObject("0.9.2342.19200300.100.4.19", "RFC 4524"),
+       /** */
+       uidObject("1.3.6.1.1.3.1", "RFC 4519"),
+       /** */
+       extensibleObject("1.3.6.1.4.1.1466.101.120.111", "RFC 4512"),
+       /** */
+       dcObject("1.3.6.1.4.1.1466.344", "RFC 4519"),
+       /** */
+       authPasswordObject("1.3.6.1.4.1.4203.1.4.7", "RFC 3112"),
+       /** */
+       namedObject("1.3.6.1.4.1.5322.13.1.1", "draft-howard-namedobject"),
+       /** */
+       inheritableLDAPSubEntry("1.3.6.1.4.1.7628.5.6.1.1", "draft-ietf-ldup-subentry"),
+       /** */
+       top("2.5.6.0", "RFC 4512"),
+       /** */
+       alias("2.5.6.1", "RFC 4512"),
+       /** */
+       country("2.5.6.2", "RFC 4519"),
+       /** */
+       locality("2.5.6.3", "RFC 4519"),
+       /** */
+       organization("2.5.6.4", "RFC 4519"),
+       /** */
+       organizationalUnit("2.5.6.5", "RFC 4519"),
+       /** */
+       person("2.5.6.6", "RFC 4519"),
+       /** */
+       organizationalPerson("2.5.6.7", "RFC 4519"),
+       /** */
+       organizationalRole("2.5.6.8", "RFC 4519"),
+       /** */
+       groupOfNames("2.5.6.9", "RFC 4519"),
+       /** */
+       residentialPerson("2.5.6.10", "RFC 4519"),
+       /** */
+       applicationProcess("2.5.6.11", "RFC 4519"),
+       /** */
+       device("2.5.6.14", "RFC 4519"),
+       /** */
+       strongAuthenticationUser("2.5.6.15", "RFC 4523"),
+       /** */
+       certificationAuthority("2.5.6.16", "RFC 4523"),
+       // /** Should be certificationAuthority-V2 */
+       // certificationAuthority_V2("2.5.6.16.2", "RFC 4523") {
+       // },
+       /** */
+       groupOfUniqueNames("2.5.6.17", "RFC 4519"),
+       /** */
+       userSecurityInformation("2.5.6.18", "RFC 4523"),
+       /** */
+       cRLDistributionPoint("2.5.6.19", "RFC 4523"),
+       /** */
+       pkiUser("2.5.6.21", "RFC 4523"),
+       /** */
+       pkiCA("2.5.6.22", "RFC 4523"),
+       /** */
+       deltaCRL("2.5.6.23", "RFC 4523"),
+       /** */
+       subschema("2.5.20.1", "RFC 4512"),
+       /** */
+       ldapSubEntry("2.16.840.1.113719.2.142.6.1.1", "draft-ietf-ldup-subentry"),
+       /** */
+       changeLogEntry("2.16.840.1.113730.3.2.1", "draft-good-ldap-changelog"),
+       /** */
+       inetOrgPerson("2.16.840.1.113730.3.2.2", "RFC 2798"),
+       /** */
+       referral("2.16.840.1.113730.3.2.6", "RFC 3296"),
+
+       // RFC 2307bis (partial)
+       /** */
+       posixAccount("1.3.6.1.1.1.2.0", "RFC 2307bis"),
+       /** */
+       posixGroup("1.3.6.1.1.1.2.2", "RFC 2307bis"),
+
+       //
+       ;
+
+       private final String oid, spec;
+       private final QName value;
+
+       private LdapObj(String oid, String spec) {
+               this.oid = oid;
+               this.spec = spec;
+               this.value = new ContentName(ArgeoNamespace.LDAP_NAMESPACE_URI, name());
+       }
+
+       public QName qName() {
+               return value;
+       }
+
+       public String getOid() {
+               return oid;
+       }
+
+       public String getSpec() {
+               return spec;
+       }
+
+       @Deprecated
+       public String property() {
+               return get();
+       }
+
+       /** #deprecated use {@link #qName()} instead. */
+//     @Deprecated
+       public String get() {
+               return RuntimeNamespaceContext.getNamespaceContext().getPrefix(LDAP_NAMESPACE_URI) + ":" + name();
+       }
+
+       @Override
+       public String getNamespace() {
+               return LDAP_NAMESPACE_URI;
+       }
+
+       @Override
+       public String getDefaultPrefix() {
+               return LDAP_DEFAULT_PREFIX;
+       }
+
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/NamingUtils.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/NamingUtils.java
new file mode 100644 (file)
index 0000000..88b76ec
--- /dev/null
@@ -0,0 +1,106 @@
+package org.argeo.api.acr.ldap;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class NamingUtils {
+       /** As per https://tools.ietf.org/html/rfc4517#section-3.3.13 */
+       private final static DateTimeFormatter utcLdapDate = DateTimeFormatter.ofPattern("uuuuMMddHHmmssX")
+                       .withZone(ZoneOffset.UTC);
+
+       /** @return null if not parseable */
+       public static Instant ldapDateToInstant(String ldapDate) {
+               try {
+                       return OffsetDateTime.parse(ldapDate, utcLdapDate).toInstant();
+               } catch (DateTimeParseException e) {
+                       return null;
+               }
+       }
+
+       /** @return null if not parseable */
+       public static ZonedDateTime ldapDateToZonedDateTime(String ldapDate) {
+               try {
+                       return OffsetDateTime.parse(ldapDate, utcLdapDate).toZonedDateTime();
+               } catch (DateTimeParseException e) {
+                       return null;
+               }
+       }
+
+       public static Calendar ldapDateToCalendar(String ldapDate) {
+               OffsetDateTime instant = OffsetDateTime.parse(ldapDate, utcLdapDate);
+               GregorianCalendar calendar = new GregorianCalendar();
+               calendar.set(Calendar.DAY_OF_MONTH, instant.get(ChronoField.DAY_OF_MONTH));
+               calendar.set(Calendar.MONTH, instant.get(ChronoField.MONTH_OF_YEAR));
+               calendar.set(Calendar.YEAR, instant.get(ChronoField.YEAR));
+               return calendar;
+       }
+
+       public static String instantToLdapDate(ZonedDateTime instant) {
+               return utcLdapDate.format(instant.withZoneSameInstant(ZoneOffset.UTC));
+       }
+
+       public static String getQueryValue(Map<String, List<String>> query, String key) {
+               if (!query.containsKey(key))
+                       return null;
+               List<String> val = query.get(key);
+               if (val.size() == 1)
+                       return val.get(0);
+               else
+                       throw new IllegalArgumentException("There are " + val.size() + " value(s) for " + key);
+       }
+
+       public static Map<String, List<String>> queryToMap(URI uri) {
+               return queryToMap(uri.getQuery());
+       }
+
+       private static Map<String, List<String>> queryToMap(String queryPart) {
+               try {
+                       final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
+                       if (queryPart == null)
+                               return query_pairs;
+                       final String[] pairs = queryPart.split("&");
+                       for (String pair : pairs) {
+                               final int idx = pair.indexOf("=");
+                               final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8.name())
+                                               : pair;
+                               if (!query_pairs.containsKey(key)) {
+                                       query_pairs.put(key, new LinkedList<String>());
+                               }
+                               final String value = idx > 0 && pair.length() > idx + 1
+                                               ? URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8.name())
+                                               : null;
+                               query_pairs.get(key).add(value);
+                       }
+                       return query_pairs;
+               } catch (UnsupportedEncodingException e) {
+                       throw new IllegalArgumentException("Cannot convert " + queryPart + " to map", e);
+               }
+       }
+
+       private NamingUtils() {
+
+       }
+
+//     public static void main(String args[]) {
+//             ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC);
+//             String str = utcLdapDate.format(now);
+//             System.out.println(str);
+//             utcLdapDate.parse(str);
+//             utcLdapDate.parse("19520512000000Z");
+//     }
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/NodeOID.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/NodeOID.java
new file mode 100644 (file)
index 0000000..a68b6cb
--- /dev/null
@@ -0,0 +1,17 @@
+package org.argeo.api.acr.ldap;
+
+interface NodeOID {
+       String BASE = "1.3.6.1.4.1" + ".48308" + ".1";
+
+       // uuidgen --md5 --namespace @oid --name 1.3.6.1.4.1.48308
+       String BASE_UUID_V3 = "6869e86b-96b7-3d49-b6ab-ffffc5ad95fb";
+       
+       // uuidgen --sha1 --namespace @oid --name 1.3.6.1.4.1.48308
+       String BASE_UUID_V5 = "58873947-460c-59a6-a7b4-28a97def5f27";
+       
+       // ATTRIBUTE TYPES
+       String ATTRIBUTE_TYPES = BASE + ".4";
+
+       // OBJECT CLASSES
+       String OBJECT_CLASSES = BASE + ".6";
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/SpecifiedName.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/SpecifiedName.java
new file mode 100644 (file)
index 0000000..19e7240
--- /dev/null
@@ -0,0 +1,20 @@
+package org.argeo.api.acr.ldap;
+
+/**
+ * A name which has been specified and for which an id has been defined
+ * (typically an OID).
+ */
+interface SpecifiedName {
+       /** The name */
+       String name();
+
+       /** An RFC or the URLof some specification */
+       default String getSpec() {
+               return null;
+       }
+
+       /** Typically an OID */
+       default String getID() {
+               return getClass().getName() + "." + name();
+       }
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/spi/ContentNamespace.java b/org.argeo.api.acr/src/org/argeo/api/acr/spi/ContentNamespace.java
new file mode 100644 (file)
index 0000000..f91a177
--- /dev/null
@@ -0,0 +1,13 @@
+package org.argeo.api.acr.spi;
+
+import java.net.URL;
+
+/** A namespace and its default prefix, possibly with a schema definition. */
+public interface ContentNamespace {
+       String getDefaultPrefix();
+
+       String getNamespaceURI();
+
+       URL getSchemaResource();
+
+}
index 7134007b99e7e09d52d057601b726797d9fe9651..06ee43aa74fe00e19ddf24a4810498d1428d2e00 100644 (file)
@@ -7,7 +7,7 @@ import org.argeo.api.acr.ContentRepository;
 
 /** A {@link ContentRepository} implementation. */
 public interface ProvidedRepository extends ContentRepository {
-       void registerTypes(String prefix, String namespaceURI, String schemaSystemId);
+       void registerTypes(ContentNamespace... namespaces);
 
        ContentProvider getMountContentProvider(Content mountPoint, boolean initialize, QName... types);
 
index 9c4f6e633a5918ac0b50d053c0a541d66a76ab36..5a538b57a45ec4593aca8a9267e67570393169b2 100644 (file)
@@ -22,7 +22,7 @@ public interface ProvidedSession extends ContentSession {
 
        UUID getUuid();
 
-       Content getSessionRunDir();
+//     Content getSessionRunDir();
 
        /*
         * NAMESPACE CONTEXT
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/tabular/ArrayTabularRow.java b/org.argeo.api.acr/src/org/argeo/api/acr/tabular/ArrayTabularRow.java
new file mode 100644 (file)
index 0000000..c0efe87
--- /dev/null
@@ -0,0 +1,25 @@
+package org.argeo.api.acr.tabular;
+
+import java.util.List;
+
+/** Minimal tabular row wrapping an {@link Object} array */
+public class ArrayTabularRow implements TabularRow {
+       private final Object[] arr;
+
+       public ArrayTabularRow(List<?> objs) {
+               this.arr = objs.toArray();
+       }
+
+       public Object get(Integer col) {
+               return arr[col];
+       }
+
+       public int size() {
+               return arr.length;
+       }
+
+       public Object[] toArray() {
+               return arr;
+       }
+
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularColumn.java b/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularColumn.java
new file mode 100644 (file)
index 0000000..5b9bf23
--- /dev/null
@@ -0,0 +1,41 @@
+package org.argeo.api.acr.tabular;
+
+/** The column in a tabular content */
+public class TabularColumn {
+       private String name;
+       /**
+        * JCR types, see
+        * http://www.day.com/maven/javax.jcr/javadocs/jcr-2.0/index.html
+        * ?javax/jcr/PropertyType.html
+        */
+       private Integer type;
+
+       /** column with default type */
+       public TabularColumn(String name) {
+               super();
+               this.name = name;
+       }
+
+       public TabularColumn(String name, Integer type) {
+               super();
+               this.name = name;
+               this.type = type;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       public Integer getType() {
+               return type;
+       }
+
+       public void setType(Integer type) {
+               this.type = type;
+       }
+
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularContent.java b/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularContent.java
new file mode 100644 (file)
index 0000000..ae6eb4e
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.api.acr.tabular;
+
+import java.util.List;
+
+/**
+ * Content organized as a table, possibly with headers. Only JCR types are
+ * supported even though there is not direct dependency on JCR.
+ */
+public interface TabularContent {
+       /** The headers of this table or <code>null</code> is none available. */
+       public List<TabularColumn> getColumns();
+
+       public TabularRowIterator read();
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularRow.java b/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularRow.java
new file mode 100644 (file)
index 0000000..5302cc0
--- /dev/null
@@ -0,0 +1,13 @@
+package org.argeo.api.acr.tabular;
+
+/** A row of tabular data */
+public interface TabularRow {
+       /** The value at this column index */
+       public Object get(Integer col);
+
+       /** The raw objects (direct references) */
+       public Object[] toArray();
+
+       /** Number of columns */
+       public int size();
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularRowIterator.java b/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularRowIterator.java
new file mode 100644 (file)
index 0000000..768c593
--- /dev/null
@@ -0,0 +1,12 @@
+package org.argeo.api.acr.tabular;
+
+import java.util.Iterator;
+
+/** Navigation of rows */
+public interface TabularRowIterator extends Iterator<TabularRow> {
+       /**
+        * Current row number, has to be incremented by each call to next() ; starts at 0, will
+        * therefore be 1 for the first row returned.
+        */
+       public Long getCurrentRowNumber();
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularWriter.java b/org.argeo.api.acr/src/org/argeo/api/acr/tabular/TabularWriter.java
new file mode 100644 (file)
index 0000000..f1d555f
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.api.acr.tabular;
+
+
+/** Write to a tabular content */
+public interface TabularWriter {
+       /** Append a new row of data */
+       public void appendRow(Object[] row);
+
+       /** Finish persisting data and release resources */
+       public void close();
+}
diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/tabular/package-info.java b/org.argeo.api.acr/src/org/argeo/api/acr/tabular/package-info.java
new file mode 100644 (file)
index 0000000..06acbc5
--- /dev/null
@@ -0,0 +1,2 @@
+/** Tabular format API. */
+package org.argeo.api.acr.tabular;
\ No newline at end of file
index b2a12a603dc416ba2d4e26f99086b0dcb5e437fd..935247feee47d8b1fa42617b7442cd48ee92a649 100644 (file)
@@ -1,5 +1,6 @@
 package org.argeo.api.cli;
 
+/** Exception thrown when the provided arguments are not correct. */
 public class CommandArgsException extends IllegalArgumentException {
        private static final long serialVersionUID = -7271050747105253935L;
        private String commandName;
index b82308a2ba39f56ead0a3cc152b5d58926433fa9..5bbfcfa070d7cee0a2e13c722c4561b6812ec8c8 100644 (file)
@@ -18,8 +18,6 @@ import org.apache.commons.cli.ParseException;
 
 /** Base class for a CLI managing sub commands. */
 public abstract class CommandsCli implements DescribedCommand<Object> {
-       public final static String HELP = "help";
-
        private final String commandName;
        private Map<String, Function<List<String>, ?>> commands = new TreeMap<>();
 
@@ -33,11 +31,17 @@ public abstract class CommandsCli implements DescribedCommand<Object> {
        public Object apply(List<String> args) {
                String cmd = null;
                List<String> newArgs = new ArrayList<>();
+               boolean isHelpOption = false;
                try {
                        CommandLineParser clParser = new DefaultParser();
                        CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true);
                        List<String> leftOvers = commonCl.getArgList();
                        for (String arg : leftOvers) {
+                               if (arg.equals("--" + HelpCommand.HELP_OPTION.getLongOpt())) {
+                                       isHelpOption = true;
+                                       // TODO break?
+                               }
+
                                if (!arg.startsWith("-") && cmd == null) {
                                        cmd = arg;
                                } else {
@@ -50,6 +54,18 @@ public abstract class CommandsCli implements DescribedCommand<Object> {
                }
 
                Function<List<String>, ?> function = cmd != null ? getCommand(cmd) : getDefaultCommand();
+
+               // --help option
+               if (!(function instanceof CommandsCli))
+                       if (function instanceof DescribedCommand<?> command)
+                               if (isHelpOption) {
+                                       throw new PrintHelpRequestException(cmd, this);
+//                                     StringWriter out = new StringWriter();
+//                                     HelpCommand.printHelp(command, out);
+//                                     System.out.println(out.toString());
+//                                     return null;
+                               }
+
                if (function == null)
                        throw new IllegalArgumentException("Uknown command " + cmd);
                try {
@@ -85,7 +101,7 @@ public abstract class CommandsCli implements DescribedCommand<Object> {
 
        protected void addCommandsCli(CommandsCli commandsCli) {
                addCommand(commandsCli.getCommandName(), commandsCli);
-               commandsCli.addCommand(HELP, new HelpCommand(this, commandsCli));
+               commandsCli.addCommand(HelpCommand.HELP, new HelpCommand(this, commandsCli));
        }
 
        public String getCommandName() {
@@ -101,7 +117,7 @@ public abstract class CommandsCli implements DescribedCommand<Object> {
        }
 
        public HelpCommand getHelpCommand() {
-               return (HelpCommand) getCommand(HELP);
+               return (HelpCommand) getCommand(HelpCommand.HELP);
        }
 
        public Function<List<String>, String> getDefaultCommand() {
@@ -111,10 +127,15 @@ public abstract class CommandsCli implements DescribedCommand<Object> {
        /** In order to implement quickly a main method. */
        public static void mainImpl(CommandsCli cli, String[] args) {
                try {
-                       cli.addCommand(CommandsCli.HELP, new HelpCommand(null, cli));
+                       cli.addCommand(HelpCommand.HELP, new HelpCommand(null, cli));
                        Object output = cli.apply(Arrays.asList(args));
-                       System.out.println(output);
+                       if (output != null)
+                               System.out.println(output);
                        System.exit(0);
+               } catch (PrintHelpRequestException e) {
+                       StringWriter out = new StringWriter();
+                       HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out);
+                       System.out.println(out.toString());
                } catch (CommandArgsException e) {
                        System.err.println("Wrong arguments " + Arrays.toString(args) + ": " + e.getMessage());
                        Throwable cause = e.getCause();
index 7a9d5d90111ece240c66576b51d5f5613776f7d1..51cb2cecaa2558698d63a30d89d7a479fbda71a6 100644 (file)
@@ -41,6 +41,11 @@ public interface DescribedCommand<T> extends Function<List<String>, T> {
                        Object output = command.apply(Arrays.asList(args));
                        System.out.println(output);
                        System.exit(0);
+               } catch (PrintHelpRequestException e) {
+                       StringWriter out = new StringWriter();
+                       HelpCommand.printHelp(command, out);
+                       System.out.println(out.toString());
+                       System.exit(1);
                } catch (IllegalArgumentException e) {
                        StringWriter out = new StringWriter();
                        HelpCommand.printHelp(command, out);
index d5285a60c25f1bf297e5dc9a49e9a63f35edea75..cd51d76953b6e4f63b23914ad9edbac4313e45dd 100644 (file)
@@ -6,10 +6,20 @@ import java.util.List;
 import java.util.function.Function;
 
 import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
 
 /** A special command that can describe {@link DescribedCommand}. */
 public class HelpCommand implements DescribedCommand<String> {
+       /**
+        * System property forcing the root command to this value (typically the name of
+        * a script).
+        */
+       public final static String ROOT_COMMAND_PROPERTY = "org.argeo.api.cli.rootCommand";
+
+       final static String HELP = "help";
+       final static Option HELP_OPTION = Option.builder().longOpt(HELP).desc("print this help").build();
+
        private CommandsCli commandsCli;
        private CommandsCli parentCommandsCli;
 
@@ -91,6 +101,9 @@ public class HelpCommand implements DescribedCommand<String> {
                if (hc.getParentCommandsCli() != null) {
                        return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName();
                } else {
+                       String rootCommand = System.getProperty(ROOT_COMMAND_PROPERTY);
+                       if (rootCommand != null)
+                               return rootCommand;
                        return commandsCli.getCommandName();
                }
        }
@@ -99,17 +112,25 @@ public class HelpCommand implements DescribedCommand<String> {
                String usage = "java " + command.getClass().getName()
                                + (command.getUsage() != null ? " " + command.getUsage() : "");
                HelpFormatter formatter = new HelpFormatter();
-               formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
-                               helpLeftPad, helpDescPad, command.getExamples(), false);
+               Options options = command.getOptions();
+               options.addOption(HelpCommand.HELP_OPTION);
+               formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad,
+                               helpDescPad, command.getExamples(), false);
 
        }
 
        public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) {
+               if (commandName == null) {
+                       printHelp(commandsCli, out);
+                       return;
+               }
                DescribedCommand<?> command = (DescribedCommand<?>) commandsCli.getCommand(commandName);
                String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command);
                HelpFormatter formatter = new HelpFormatter();
-               formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), command.getOptions(),
-                               helpLeftPad, helpDescPad, command.getExamples(), false);
+               Options options = command.getOptions();
+               options.addOption(HelpCommand.HELP_OPTION);
+               formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad,
+                               helpDescPad, command.getExamples(), false);
 
        }
 
diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/PrintHelpRequestException.java b/org.argeo.api.cli/src/org/argeo/api/cli/PrintHelpRequestException.java
new file mode 100644 (file)
index 0000000..017386b
--- /dev/null
@@ -0,0 +1,29 @@
+package org.argeo.api.cli;
+
+/** An exception indicating that help should be printed. */
+class PrintHelpRequestException extends RuntimeException {
+
+       private static final long serialVersionUID = -9029122270660656639L;
+
+       private String commandName;
+       private volatile CommandsCli commandsCli;
+
+       public PrintHelpRequestException(String commandName, CommandsCli commandsCli) {
+               super();
+               this.commandName = commandName;
+               this.commandsCli = commandsCli;
+       }
+
+       public static long getSerialversionuid() {
+               return serialVersionUID;
+       }
+
+       public String getCommandName() {
+               return commandName;
+       }
+
+       public CommandsCli getCommandsCli() {
+               return commandsCli;
+       }
+
+}
index 51c4e663c9a1a6e5cc7f1507e230b6dd61e42840..36cde6410b661217d9016bf03cb81b3179082af7 100644 (file)
@@ -1,4 +1,6 @@
 Import-Package: \
-javax.security.*
+javax.transaction.xa,\
+javax.security.*,\
+org.osgi.service.useradmin,\
 
 Export-Package: org.argeo.api.cms.*
\ No newline at end of file
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsAuthorization.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsAuthorization.java
new file mode 100644 (file)
index 0000000..5d3a695
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.api.cms.directory;
+
+import org.osgi.service.useradmin.Authorization;
+
+/** An authorisation to a CMS system. */
+public interface CmsAuthorization extends Authorization {
+       /** The role which did imply this role, <code>null</code> if a direct role. */
+       default String getImplyingRole(String role) {
+               return null;
+       }
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsDirectory.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsDirectory.java
new file mode 100644 (file)
index 0000000..f5b78ac
--- /dev/null
@@ -0,0 +1,32 @@
+package org.argeo.api.cms.directory;
+
+import java.util.Optional;
+
+import org.argeo.api.cms.transaction.WorkControl;
+
+/** An information directory (typically LDAP). */
+public interface CmsDirectory extends HierarchyUnit {
+       String getName();
+
+       /** Whether this directory is read only. */
+       boolean isReadOnly();
+
+       /** Whether this directory is disabled. */
+       boolean isDisabled();
+
+       /** The realm (typically Kerberos) of this directory. */
+       Optional<String> getRealm();
+
+       /** Sets the transaction control used by this directory when editing. */
+       void setTransactionControl(WorkControl transactionControl);
+
+       /*
+        * HIERARCHY
+        */
+
+       /** The hierarchy unit at this path. */
+       HierarchyUnit getHierarchyUnit(String path);
+
+       /** Create a new hierarchy unit. */
+       HierarchyUnit createHierarchyUnit(String path);
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsGroup.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsGroup.java
new file mode 100644 (file)
index 0000000..410d391
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.api.cms.directory;
+
+import org.osgi.service.useradmin.Group;
+
+/** A group in a user directroy. */
+public interface CmsGroup extends Group, CmsUser {
+//     List<LdapName> getMemberNames();
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsUser.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsUser.java
new file mode 100644 (file)
index 0000000..f8f40a1
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.api.cms.directory;
+
+import org.osgi.service.useradmin.User;
+
+/**
+ * An entity with credentials which can log in to a system. Can be a real person
+ * or not.
+ */
+public interface CmsUser extends User {
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsUserManager.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/CmsUserManager.java
new file mode 100644 (file)
index 0000000..7693f67
--- /dev/null
@@ -0,0 +1,125 @@
+package org.argeo.api.cms.directory;
+
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.xml.namespace.QName;
+
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Provide method interfaces to manage user concepts without accessing directly
+ * the userAdmin.
+ */
+public interface CmsUserManager {
+       Map<String, String> getKnownBaseDns(boolean onlyWritable);
+
+       Set<UserDirectory> getUserDirectories();
+
+       // CurrentUser
+       /** Returns the e-mail of the current logged in user */
+       String getMyMail();
+
+       // Other users
+       /** Returns a {@link User} given a username */
+       CmsUser getUser(String username);
+
+       /** Can be a group or a user */
+       String getUserDisplayName(String dn);
+
+       /** Can be a group or a user */
+       String getUserMail(String dn);
+
+       /** Lists all roles of the given user */
+       String[] getUserRoles(String dn);
+
+       /** Checks if the passed user belongs to the passed role */
+       boolean isUserInRole(String userDn, String roleDn);
+
+       // Search
+       /** Returns a filtered list of roles */
+       Role[] getRoles(String filter);
+
+       /** Recursively lists users in a given group. */
+       Set<CmsUser> listUsersInGroup(String groupDn, String filter);
+
+       /** Search among groups including system roles and users if needed */
+       List<CmsUser> listGroups(String filter, boolean includeUsers, boolean includeSystemRoles);
+
+//     /**
+//      * Lists functional accounts, that is users with regular access to the system
+//      * under this functional hierarchy unit (which probably have technical direct
+//      * sub hierarchy units), excluding groups which are not explicitly users.
+//      */
+//     Set<User> listAccounts(HierarchyUnit hierarchyUnit, boolean deep);
+
+       /*
+        * EDITION
+        */
+       /** Creates a new user. */
+       CmsUser createUser(String username, Map<String, Object> properties, Map<String, Object> credentials);
+
+       /** Created a new group. */
+       CmsGroup createGroup(String dn);
+
+       /** Creates a group. */
+       CmsGroup getOrCreateGroup(HierarchyUnit groups, String commonName);
+
+       /** Creates a new system role. */
+       CmsGroup getOrCreateSystemRole(HierarchyUnit roles, QName systemRole);
+
+       /** Add additional object classes to this role. */
+       void addObjectClasses(Role role, Set<String> objectClasses, Map<String, Object> additionalProperties);
+
+       /** Add additional object classes to this hierarchy unit. */
+       void addObjectClasses(HierarchyUnit hierarchyUnit, Set<String> objectClasses,
+                       Map<String, Object> additionalProperties);
+
+       /** Add a member to this group. */
+       void addMember(CmsGroup group, Role role);
+
+       /** Remove a member from this group. */
+       void removeMember(CmsGroup group, Role role);
+       
+       void edit(Runnable action);
+
+       /* MISCELLANEOUS */
+       /** Returns the dn of a role given its local ID */
+       String buildDefaultDN(String localId, int type);
+
+       /** Exposes the main default domain name for this instance */
+       String getDefaultDomainName();
+
+       /**
+        * Search for a {@link User} (might also be a group) whose uid or cn is equals
+        * to localId within the various user repositories defined in the current
+        * context.
+        */
+       CmsUser getUserFromLocalId(String localId);
+
+       void changeOwnPassword(char[] oldPassword, char[] newPassword);
+
+       void resetPassword(String username, char[] newPassword);
+
+       @Deprecated
+       String addSharedSecret(String username, int hours);
+
+//     String addSharedSecret(String username, String authInfo, String authToken);
+
+       void addAuthToken(String userDn, String token, Integer hours, String... roles);
+
+       void addAuthToken(String userDn, String token, ZonedDateTime expiryDate, String... roles);
+
+       void expireAuthToken(String token);
+
+       void expireAuthTokens(Subject subject);
+
+       UserDirectory getDirectory(Role role);
+
+       /** Create a new hierarchy unit. Does nothing if it already exists. */
+       HierarchyUnit getOrCreateHierarchyUnit(UserDirectory directory, String path);
+}
\ No newline at end of file
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/DirectoryDigestUtils.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/DirectoryDigestUtils.java
new file mode 100644 (file)
index 0000000..dabcfe8
--- /dev/null
@@ -0,0 +1,114 @@
+package org.argeo.api.cms.directory;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+/** Utilities around digests, mostly those related to passwords. */
+public class DirectoryDigestUtils {
+       public final static String PASSWORD_SCHEME_SHA = "SHA";
+       public final static String PASSWORD_SCHEME_PBKDF2_SHA256 = "PBKDF2_SHA256";
+
+       public static byte[] sha1(byte[] bytes) {
+               try {
+                       MessageDigest digest = MessageDigest.getInstance("SHA1");
+                       digest.update(bytes);
+                       byte[] checksum = digest.digest();
+                       return checksum;
+               } catch (NoSuchAlgorithmException e) {
+                       throw new IllegalStateException("Cannot SHA1 digest", e);
+               }
+       }
+
+       public static byte[] toPasswordScheme(String passwordScheme, char[] password, byte[] salt, Integer iterations,
+                       Integer keyLength) {
+               try {
+                       if (PASSWORD_SCHEME_SHA.equals(passwordScheme)) {
+                               MessageDigest digest = MessageDigest.getInstance("SHA1");
+                               byte[] bytes = charsToBytes(password);
+                               digest.update(bytes);
+                               return digest.digest();
+                       } else if (PASSWORD_SCHEME_PBKDF2_SHA256.equals(passwordScheme)) {
+                               KeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength);
+
+                               SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+                               final int ITERATION_LENGTH = 4;
+                               byte[] key = f.generateSecret(spec).getEncoded();
+                               byte[] result = new byte[ITERATION_LENGTH + salt.length + key.length];
+                               byte iterationsArr[] = new BigInteger(iterations.toString()).toByteArray();
+                               if (iterationsArr.length < ITERATION_LENGTH) {
+                                       Arrays.fill(result, 0, ITERATION_LENGTH - iterationsArr.length, (byte) 0);
+                                       System.arraycopy(iterationsArr, 0, result, ITERATION_LENGTH - iterationsArr.length,
+                                                       iterationsArr.length);
+                               } else {
+                                       System.arraycopy(iterationsArr, 0, result, 0, ITERATION_LENGTH);
+                               }
+                               System.arraycopy(salt, 0, result, ITERATION_LENGTH, salt.length);
+                               System.arraycopy(key, 0, result, ITERATION_LENGTH + salt.length, key.length);
+                               return result;
+                       } else {
+                               throw new UnsupportedOperationException("Unkown password scheme " + passwordScheme);
+                       }
+               } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+                       throw new IllegalStateException("Cannot digest", e);
+               }
+       }
+
+       public static char[] bytesToChars(Object obj) {
+               if (obj instanceof char[])
+                       return (char[]) obj;
+               if (!(obj instanceof byte[]))
+                       throw new IllegalArgumentException(obj.getClass() + " is not a byte array");
+               ByteBuffer fromBuffer = ByteBuffer.wrap((byte[]) obj);
+               CharBuffer toBuffer = StandardCharsets.UTF_8.decode(fromBuffer);
+               char[] res = Arrays.copyOfRange(toBuffer.array(), toBuffer.position(), toBuffer.limit());
+               // Arrays.fill(fromBuffer.array(), (byte) 0); // clear sensitive data
+               // Arrays.fill((byte[]) obj, (byte) 0); // clear sensitive data
+               // Arrays.fill(toBuffer.array(), '\u0000'); // clear sensitive data
+               return res;
+       }
+
+       public static byte[] charsToBytes(char[] chars) {
+               CharBuffer charBuffer = CharBuffer.wrap(chars);
+               ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(charBuffer);
+               byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
+               // Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
+               // Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
+               return bytes;
+       }
+
+       public static String sha1str(String str) {
+               byte[] hash = sha1(str.getBytes(StandardCharsets.UTF_8));
+               return encodeHexString(hash);
+       }
+
+       final private static char[] hexArray = "0123456789abcdef".toCharArray();
+
+       /**
+        * From
+        * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
+        * -a-hex-string-in-java
+        */
+       public static String encodeHexString(byte[] bytes) {
+               char[] hexChars = new char[bytes.length * 2];
+               for (int j = 0; j < bytes.length; j++) {
+                       int v = bytes[j] & 0xFF;
+                       hexChars[j * 2] = hexArray[v >>> 4];
+                       hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+               }
+               return new String(hexChars);
+       }
+
+       /** singleton */
+       private DirectoryDigestUtils() {
+       }
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/HierarchyUnit.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/HierarchyUnit.java
new file mode 100644 (file)
index 0000000..52509e8
--- /dev/null
@@ -0,0 +1,56 @@
+package org.argeo.api.cms.directory;
+
+import java.util.Dictionary;
+import java.util.Locale;
+
+/** A unit within the high-level organisational structure of a directory. */
+public interface HierarchyUnit {
+       /** Name to use in paths. */
+       String getHierarchyUnitName();
+
+       /** Name to use in UI. */
+       String getHierarchyUnitLabel(Locale locale);
+
+       /**
+        * The parent {@link HierarchyUnit}, or <code>null</code> if a
+        * {@link CmsDirectory}.
+        */
+       HierarchyUnit getParent();
+
+       /** Direct children {@link HierarchyUnit}s. */
+       Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly);
+
+       /**
+        * Whether this is an arbitrary named and placed {@link HierarchyUnit}.
+        * 
+        * @return <code>true</code> if functional, <code>false</code> is technical
+        *         (e.g. People, Groups, etc.)
+        */
+       default boolean isFunctional() {
+               return isType(Type.FUNCTIONAL);
+       }
+
+       boolean isType(Type type);
+
+       /** A technical direct child. */
+       HierarchyUnit getDirectChild(Type type);
+
+       /**
+        * The base of this organisational unit within the hierarchy. This would
+        * typically be an LDAP base DN.
+        */
+       String getBase();
+
+       /** The related {@link CmsDirectory}. */
+       CmsDirectory getDirectory();
+
+       /** Its metadata (typically LDAP attributes). */
+       Dictionary<String, Object> getProperties();
+
+       enum Type {
+               PEOPLE, //
+               GROUPS, //
+               ROLES, //
+               FUNCTIONAL;
+       }
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/directory/UserDirectory.java b/org.argeo.api.cms/src/org/argeo/api/cms/directory/UserDirectory.java
new file mode 100644 (file)
index 0000000..1f0ecdf
--- /dev/null
@@ -0,0 +1,17 @@
+package org.argeo.api.cms.directory;
+
+import org.osgi.service.useradmin.Role;
+
+/** Information about a user directory. */
+public interface UserDirectory extends CmsDirectory {
+
+       HierarchyUnit getHierarchyUnit(Role role);
+
+       Iterable<? extends Role> getHierarchyUnitRoles(HierarchyUnit hierarchyUnit, String filter, boolean deep);
+
+       String getRolePath(Role role);
+
+       String getRoleSimpleName(Role role);
+
+       Role getRoleByPath(String path);
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/keyring/CryptoKeyring.java b/org.argeo.api.cms/src/org/argeo/api/cms/keyring/CryptoKeyring.java
new file mode 100644 (file)
index 0000000..454f8b4
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.api.cms.keyring;
+
+/**
+ * Marker interface for an advanced keyring based on cryptography.
+ */
+public interface CryptoKeyring extends Keyring {
+       public void changePassword(char[] oldPassword, char[] newPassword);
+
+       public void unlock(char[] password);
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/keyring/Keyring.java b/org.argeo.api.cms/src/org/argeo/api/cms/keyring/Keyring.java
new file mode 100644 (file)
index 0000000..efc9455
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.api.cms.keyring;
+
+import java.io.InputStream;
+
+/**
+ * Access to private (typically encrypted) data. The keyring is responsible for
+ * retrieving the necessary credentials. <b>Experimental. This API may
+ * change.</b>
+ */
+public interface Keyring {
+       /**
+        * Returns the confidential information as chars. Must ask for it if it is
+        * not stored.
+        */
+       public char[] getAsChars(String path);
+
+       /**
+        * Returns the confidential information as a stream. Must ask for it if it
+        * is not stored.
+        */
+       public InputStream getAsStream(String path);
+
+       public void set(String path, char[] arr);
+
+       public void set(String path, InputStream in);
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/keyring/PBEKeySpecCallback.java b/org.argeo.api.cms/src/org/argeo/api/cms/keyring/PBEKeySpecCallback.java
new file mode 100644 (file)
index 0000000..6a7ce19
--- /dev/null
@@ -0,0 +1,63 @@
+package org.argeo.api.cms.keyring;
+
+import javax.crypto.spec.PBEKeySpec;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.PasswordCallback;
+
+/**
+ * All information required to set up a {@link PBEKeySpec} bar the password
+ * itself (use a {@link PasswordCallback})
+ */
+public class PBEKeySpecCallback implements Callback {
+       private String secretKeyFactory;
+       private byte[] salt;
+       private Integer iterationCount;
+       /** Can be null for some algorithms */
+       private Integer keyLength;
+       /** Can be null, will trigger secret key encryption if not */
+       private String secretKeyEncryption;
+
+       private String encryptedPasswordHashCipher;
+       private byte[] encryptedPasswordHash;
+
+       public void set(String secretKeyFactory, byte[] salt,
+                       Integer iterationCount, Integer keyLength,
+                       String secretKeyEncryption) {
+               this.secretKeyFactory = secretKeyFactory;
+               this.salt = salt;
+               this.iterationCount = iterationCount;
+               this.keyLength = keyLength;
+               this.secretKeyEncryption = secretKeyEncryption;
+//             this.encryptedPasswordHashCipher = encryptedPasswordHashCipher;
+//             this.encryptedPasswordHash = encryptedPasswordHash;
+       }
+
+       public String getSecretKeyFactory() {
+               return secretKeyFactory;
+       }
+
+       public byte[] getSalt() {
+               return salt;
+       }
+
+       public Integer getIterationCount() {
+               return iterationCount;
+       }
+
+       public Integer getKeyLength() {
+               return keyLength;
+       }
+
+       public String getSecretKeyEncryption() {
+               return secretKeyEncryption;
+       }
+
+       public String getEncryptedPasswordHashCipher() {
+               return encryptedPasswordHashCipher;
+       }
+
+       public byte[] getEncryptedPasswordHash() {
+               return encryptedPasswordHash;
+       }
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/keyring/package-info.java b/org.argeo.api.cms/src/org/argeo/api/cms/keyring/package-info.java
new file mode 100644 (file)
index 0000000..7f61e09
--- /dev/null
@@ -0,0 +1,2 @@
+/** Argeo CMS reusable security components. */
+package org.argeo.api.cms.keyring;
\ No newline at end of file
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/AbstractWorkingCopy.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/AbstractWorkingCopy.java
new file mode 100644 (file)
index 0000000..928acad
--- /dev/null
@@ -0,0 +1,48 @@
+package org.argeo.api.cms.transaction;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class AbstractWorkingCopy<DATA, ATTR, ID> implements WorkingCopy<DATA, ATTR, ID> {
+       private Map<ID, DATA> newData = new HashMap<ID, DATA>();
+       private Map<ID, ATTR> modifiedData = new HashMap<ID, ATTR>();
+       private Map<ID, DATA> deletedData = new HashMap<ID, DATA>();
+
+       protected abstract ID getId(DATA data);
+
+       protected abstract ATTR cloneAttributes(DATA data);
+
+       public void cleanUp() {
+               // clean collections
+               newData.clear();
+               newData = null;
+               modifiedData.clear();
+               modifiedData = null;
+               deletedData.clear();
+               deletedData = null;
+       }
+
+       public boolean noModifications() {
+               return newData.size() == 0 && modifiedData.size() == 0 && deletedData.size() == 0;
+       }
+
+       public void startEditing(DATA user) {
+               ID id = getId(user);
+               if (modifiedData.containsKey(id))
+                       throw new IllegalStateException("Already editing " + id);
+               modifiedData.put(id, cloneAttributes(user));
+       }
+
+       public Map<ID, DATA> getNewData() {
+               return newData;
+       }
+
+       public Map<ID, DATA> getDeletedData() {
+               return deletedData;
+       }
+
+       public Map<ID, ATTR> getModifiedData() {
+               return modifiedData;
+       }
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/JtaStatusAdapter.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/JtaStatusAdapter.java
new file mode 100644 (file)
index 0000000..2ba6c0d
--- /dev/null
@@ -0,0 +1,61 @@
+package org.argeo.api.cms.transaction;
+
+/** JTA transaction status. */
+public class JtaStatusAdapter implements TransactionStatusAdapter<Integer> {
+       private static final Integer STATUS_ACTIVE = 0;
+       private static final Integer STATUS_COMMITTED = 3;
+       private static final Integer STATUS_COMMITTING = 8;
+       private static final Integer STATUS_MARKED_ROLLBACK = 1;
+       private static final Integer STATUS_NO_TRANSACTION = 6;
+       private static final Integer STATUS_PREPARED = 2;
+       private static final Integer STATUS_PREPARING = 7;
+       private static final Integer STATUS_ROLLEDBACK = 4;
+       private static final Integer STATUS_ROLLING_BACK = 9;
+//     private static final Integer STATUS_UNKNOWN = 5;
+
+       @Override
+       public Integer getActiveStatus() {
+               return STATUS_ACTIVE;
+       }
+
+       @Override
+       public Integer getPreparingStatus() {
+               return STATUS_PREPARING;
+       }
+
+       @Override
+       public Integer getMarkedRollbackStatus() {
+               return STATUS_MARKED_ROLLBACK;
+       }
+
+       @Override
+       public Integer getPreparedStatus() {
+               return STATUS_PREPARED;
+       }
+
+       @Override
+       public Integer getCommittingStatus() {
+               return STATUS_COMMITTING;
+       }
+
+       @Override
+       public Integer getCommittedStatus() {
+               return STATUS_COMMITTED;
+       }
+
+       @Override
+       public Integer getRollingBackStatus() {
+               return STATUS_ROLLING_BACK;
+       }
+
+       @Override
+       public Integer getRolledBackStatus() {
+               return STATUS_ROLLEDBACK;
+       }
+
+       @Override
+       public Integer getNoTransactionStatus() {
+               return STATUS_NO_TRANSACTION;
+       }
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleRollbackException.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleRollbackException.java
new file mode 100644 (file)
index 0000000..39ed9b9
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.api.cms.transaction;
+
+/** Internal unchecked rollback exception. */
+class SimpleRollbackException extends RuntimeException {
+       private static final long serialVersionUID = 8055601819719780566L;
+
+       public SimpleRollbackException() {
+               super();
+       }
+
+       public SimpleRollbackException(Throwable cause) {
+               super(cause);
+       }
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleTransaction.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleTransaction.java
new file mode 100644 (file)
index 0000000..f2bb907
--- /dev/null
@@ -0,0 +1,160 @@
+package org.argeo.api.cms.transaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+/** Simple implementation of an XA transaction. */
+class SimpleTransaction<T>
+//implements Transaction, Status 
+{
+       private final Xid xid;
+       private T status;
+       private final List<XAResource> xaResources = new ArrayList<XAResource>();
+
+       private final SimpleTransactionManager transactionManager;
+       private TransactionStatusAdapter<T> tsa;
+
+       public SimpleTransaction(SimpleTransactionManager transactionManager, TransactionStatusAdapter<T> tsa) {
+               this.tsa = tsa;
+               this.status = tsa.getActiveStatus();
+               this.xid = new UuidXid();
+               this.transactionManager = transactionManager;
+       }
+
+       public synchronized void commit()
+//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+//                     SecurityException, IllegalStateException, SystemException 
+       {
+               status = tsa.getPreparingStatus();
+               for (XAResource xaRes : xaResources) {
+                       if (status.equals(tsa.getMarkedRollbackStatus()))
+                               break;
+                       try {
+                               xaRes.prepare(xid);
+                       } catch (XAException e) {
+                               status = tsa.getMarkedRollbackStatus();
+                               error("Cannot prepare " + xaRes + " for " + xid, e);
+                       }
+               }
+               if (status.equals(tsa.getMarkedRollbackStatus())) {
+                       rollback();
+                       throw new SimpleRollbackException();
+               }
+               status = tsa.getPreparedStatus();
+
+               status = tsa.getCommittingStatus();
+               for (XAResource xaRes : xaResources) {
+                       if (status.equals(tsa.getMarkedRollbackStatus()))
+                               break;
+                       try {
+                               xaRes.commit(xid, false);
+                       } catch (XAException e) {
+                               status = tsa.getMarkedRollbackStatus();
+                               error("Cannot prepare " + xaRes + " for " + xid, e);
+                       }
+               }
+               if (status.equals(tsa.getMarkedRollbackStatus())) {
+                       rollback();
+                       throw new SimpleRollbackException();
+               }
+
+               // complete
+               status = tsa.getCommittedStatus();
+               clearResources(XAResource.TMSUCCESS);
+               transactionManager.unregister(xid);
+       }
+
+       public synchronized void rollback()
+//                     throws IllegalStateException, SystemException 
+       {
+               status = tsa.getRollingBackStatus();
+               for (XAResource xaRes : xaResources) {
+                       try {
+                               xaRes.rollback(xid);
+                       } catch (XAException e) {
+                               error("Cannot rollback " + xaRes + " for " + xid, e);
+                       }
+               }
+
+               // complete
+               status = tsa.getRolledBackStatus();
+               clearResources(XAResource.TMFAIL);
+               transactionManager.unregister(xid);
+       }
+
+       public synchronized boolean enlistResource(XAResource xaRes)
+//                     throws RollbackException, IllegalStateException, SystemException 
+       {
+               if (xaResources.add(xaRes)) {
+                       try {
+                               xaRes.start(getXid(), XAResource.TMNOFLAGS);
+                               return true;
+                       } catch (XAException e) {
+                               error("Cannot enlist " + xaRes, e);
+                               return false;
+                       }
+               } else
+                       return false;
+       }
+
+       public synchronized boolean delistResource(XAResource xaRes, int flag)
+//                     throws IllegalStateException, SystemException 
+       {
+               if (xaResources.remove(xaRes)) {
+                       try {
+                               xaRes.end(getXid(), flag);
+                       } catch (XAException e) {
+                               error("Cannot delist " + xaRes, e);
+                               return false;
+                       }
+                       return true;
+               } else
+                       return false;
+       }
+
+       protected void clearResources(int flag) {
+               for (XAResource xaRes : xaResources)
+                       try {
+                               xaRes.end(getXid(), flag);
+                       } catch (XAException e) {
+                               error("Cannot end " + xaRes, e);
+                       }
+               xaResources.clear();
+       }
+
+       protected void error(Object obj, Exception e) {
+               System.err.println(obj);
+               e.printStackTrace();
+       }
+
+       public synchronized T getStatus()
+//                     throws SystemException 
+       {
+               return status;
+       }
+
+//     public void registerSynchronization(Synchronization sync)
+//                     throws RollbackException, IllegalStateException, SystemException {
+//             throw new UnsupportedOperationException();
+//     }
+
+       public void setRollbackOnly()
+//                     throws IllegalStateException, SystemException 
+       {
+               status = tsa.getMarkedRollbackStatus();
+       }
+
+       @Override
+       public int hashCode() {
+               return xid.hashCode();
+       }
+
+       Xid getXid() {
+               return xid;
+       }
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleTransactionManager.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/SimpleTransactionManager.java
new file mode 100644 (file)
index 0000000..ee99ccb
--- /dev/null
@@ -0,0 +1,214 @@
+package org.argeo.api.cms.transaction;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+/**
+ * Simple implementation of an XA transaction manager.
+ */
+public class SimpleTransactionManager
+// implements TransactionManager, UserTransaction 
+               implements WorkControl, WorkTransaction {
+       private ThreadLocal<SimpleTransaction<Integer>> current = new ThreadLocal<SimpleTransaction<Integer>>();
+
+       private Map<Xid, SimpleTransaction<Integer>> knownTransactions = Collections
+                       .synchronizedMap(new HashMap<Xid, SimpleTransaction<Integer>>());
+       private TransactionStatusAdapter<Integer> tsa = new JtaStatusAdapter();
+//     private SyncRegistry syncRegistry = new SyncRegistry();
+
+       /*
+        * WORK IMPLEMENTATION
+        */
+       @Override
+       public <T> T required(Callable<T> work) {
+               T res;
+               begin();
+               try {
+                       res = work.call();
+                       commit();
+               } catch (Exception e) {
+                       rollback();
+                       throw new SimpleRollbackException(e);
+               }
+               return res;
+       }
+
+       @Override
+       public WorkContext getWorkContext() {
+               return new WorkContext() {
+
+                       @Override
+                       public void registerXAResource(XAResource resource, String recoveryId) {
+                               getTransaction().enlistResource(resource);
+                       }
+               };
+       }
+
+       /*
+        * WORK TRANSACTION IMPLEMENTATION
+        */
+
+       @Override
+       public boolean isNoTransactionStatus() {
+               return tsa.getNoTransactionStatus().equals(getStatus());
+       }
+
+       /*
+        * JTA IMPLEMENTATION
+        */
+
+       public void begin()
+//                     throws NotSupportedException, SystemException 
+       {
+               if (getCurrent() != null)
+                       throw new UnsupportedOperationException("Nested transactions are not supported");
+               SimpleTransaction<Integer> transaction = new SimpleTransaction<Integer>(this, tsa);
+               knownTransactions.put(transaction.getXid(), transaction);
+               current.set(transaction);
+       }
+
+       public void commit()
+//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+//                     SecurityException, IllegalStateException, SystemException 
+       {
+               if (getCurrent() == null)
+                       throw new IllegalStateException("No transaction registered with the current thread.");
+               getCurrent().commit();
+       }
+
+       public int getStatus()
+//                     throws SystemException
+       {
+               if (getCurrent() == null)
+                       return tsa.getNoTransactionStatus();
+               return getTransaction().getStatus();
+       }
+
+       public SimpleTransaction<Integer> getTransaction()
+//                     throws SystemException 
+       {
+               return getCurrent();
+       }
+
+       protected SimpleTransaction<Integer> getCurrent()
+//                     throws SystemException 
+       {
+               SimpleTransaction<Integer> transaction = current.get();
+               if (transaction == null)
+                       return null;
+               Integer status = transaction.getStatus();
+               if (status.equals(tsa.getCommittedStatus()) || status.equals(tsa.getRolledBackStatus())) {
+                       current.remove();
+                       return null;
+               }
+               return transaction;
+       }
+
+       void unregister(Xid xid) {
+               knownTransactions.remove(xid);
+       }
+
+       public void resume(SimpleTransaction<Integer> tobj)
+//                     throws InvalidTransactionException, IllegalStateException, SystemException 
+       {
+               if (getCurrent() != null)
+                       throw new IllegalStateException("Transaction " + current.get() + " already registered");
+               current.set(tobj);
+       }
+
+       public void rollback()
+//                     throws IllegalStateException, SecurityException, SystemException 
+       {
+               if (getCurrent() == null)
+                       throw new IllegalStateException("No transaction registered with the current thread.");
+               getCurrent().rollback();
+       }
+
+       public void setRollbackOnly()
+//                     throws IllegalStateException, SystemException 
+       {
+               if (getCurrent() == null)
+                       throw new IllegalStateException("No transaction registered with the current thread.");
+               getCurrent().setRollbackOnly();
+       }
+
+       public void setTransactionTimeout(int seconds)
+//                     throws SystemException
+       {
+               throw new UnsupportedOperationException();
+       }
+
+       public SimpleTransaction<Integer> suspend()
+//                     throws SystemException
+       {
+               SimpleTransaction<Integer> transaction = getCurrent();
+               current.remove();
+               return transaction;
+       }
+
+//     public TransactionSynchronizationRegistry getTsr() {
+//             return syncRegistry;
+//     }
+//
+//     private class SyncRegistry implements TransactionSynchronizationRegistry {
+//             @Override
+//             public Object getTransactionKey() {
+//                     try {
+//                             SimpleTransaction transaction = getCurrent();
+//                             if (transaction == null)
+//                                     return null;
+//                             return getCurrent().getXid();
+//                     } catch (SystemException e) {
+//                             throw new IllegalStateException("Cannot get transaction key", e);
+//                     }
+//             }
+//
+//             @Override
+//             public void putResource(Object key, Object value) {
+//                     throw new UnsupportedOperationException();
+//             }
+//
+//             @Override
+//             public Object getResource(Object key) {
+//                     throw new UnsupportedOperationException();
+//             }
+//
+//             @Override
+//             public void registerInterposedSynchronization(Synchronization sync) {
+//                     throw new UnsupportedOperationException();
+//             }
+//
+//             @Override
+//             public int getTransactionStatus() {
+//                     try {
+//                             return getStatus();
+//                     } catch (SystemException e) {
+//                             throw new IllegalStateException("Cannot get status", e);
+//                     }
+//             }
+//
+//             @Override
+//             public boolean getRollbackOnly() {
+//                     try {
+//                             return getStatus() == Status.STATUS_MARKED_ROLLBACK;
+//                     } catch (SystemException e) {
+//                             throw new IllegalStateException("Cannot get status", e);
+//                     }
+//             }
+//
+//             @Override
+//             public void setRollbackOnly() {
+//                     try {
+//                             getCurrent().setRollbackOnly();
+//                     } catch (Exception e) {
+//                             throw new IllegalStateException("Cannot set rollback only", e);
+//                     }
+//             }
+//
+//     }
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/TransactionStatusAdapter.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/TransactionStatusAdapter.java
new file mode 100644 (file)
index 0000000..ab4effd
--- /dev/null
@@ -0,0 +1,22 @@
+package org.argeo.api.cms.transaction;
+
+/** Abstract the various approaches to represent transaction status. */
+public interface TransactionStatusAdapter<T> {
+       T getActiveStatus();
+
+       T getPreparingStatus();
+
+       T getMarkedRollbackStatus();
+
+       T getPreparedStatus();
+
+       T getCommittingStatus();
+
+       T getCommittedStatus();
+
+       T getRollingBackStatus();
+
+       T getRolledBackStatus();
+
+       T getNoTransactionStatus();
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/UuidXid.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/UuidXid.java
new file mode 100644 (file)
index 0000000..83358a5
--- /dev/null
@@ -0,0 +1,132 @@
+package org.argeo.api.cms.transaction;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.UUID;
+
+import javax.transaction.xa.Xid;
+
+/**
+ * Implementation of {@link Xid} based on {@link UUID}, using max significant
+ * bits as global transaction id, and least significant bits as branch
+ * qualifier.
+ */
+public class UuidXid implements Xid, Serializable {
+       private static final long serialVersionUID = -5380531989917886819L;
+       public final static int FORMAT = (int) serialVersionUID;
+
+       private final static int BYTES_PER_LONG = Long.SIZE / Byte.SIZE;
+
+       private final int format;
+       private final byte[] globalTransactionId;
+       private final byte[] branchQualifier;
+       private final String uuid;
+       private final int hashCode;
+
+       public UuidXid() {
+               this(UUID.randomUUID());
+       }
+
+       public UuidXid(UUID uuid) {
+               this.format = FORMAT;
+               this.globalTransactionId = uuidToBytes(uuid.getMostSignificantBits());
+               this.branchQualifier = uuidToBytes(uuid.getLeastSignificantBits());
+               this.uuid = uuid.toString();
+               this.hashCode = uuid.hashCode();
+       }
+
+       public UuidXid(Xid xid) {
+               this(xid.getFormatId(), xid.getGlobalTransactionId(), xid
+                               .getBranchQualifier());
+       }
+
+       private UuidXid(int format, byte[] globalTransactionId,
+                       byte[] branchQualifier) {
+               this.format = format;
+               this.globalTransactionId = globalTransactionId;
+               this.branchQualifier = branchQualifier;
+               this.uuid = bytesToUUID(globalTransactionId, branchQualifier)
+                               .toString();
+               this.hashCode = uuid.hashCode();
+       }
+
+       @Override
+       public int getFormatId() {
+               return format;
+       }
+
+       @Override
+       public byte[] getGlobalTransactionId() {
+               return Arrays.copyOf(globalTransactionId, globalTransactionId.length);
+       }
+
+       @Override
+       public byte[] getBranchQualifier() {
+               return Arrays.copyOf(branchQualifier, branchQualifier.length);
+       }
+
+       @Override
+       public int hashCode() {
+               return hashCode;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj instanceof UuidXid) {
+                       UuidXid that = (UuidXid) obj;
+                       return Arrays.equals(globalTransactionId, that.globalTransactionId)
+                                       && Arrays.equals(branchQualifier, that.branchQualifier);
+               }
+               if (obj instanceof Xid) {
+                       Xid that = (Xid) obj;
+                       return Arrays.equals(globalTransactionId,
+                                       that.getGlobalTransactionId())
+                                       && Arrays
+                                                       .equals(branchQualifier, that.getBranchQualifier());
+               }
+               return uuid.equals(obj.toString());
+       }
+
+       @Override
+       protected Object clone() throws CloneNotSupportedException {
+               return new UuidXid(format, globalTransactionId, branchQualifier);
+       }
+
+       @Override
+       public String toString() {
+               return uuid;
+       }
+
+       public UUID asUuid() {
+               return bytesToUUID(globalTransactionId, branchQualifier);
+       }
+
+       public static byte[] uuidToBytes(long bits) {
+               ByteBuffer buffer = ByteBuffer.allocate(BYTES_PER_LONG);
+               buffer.putLong(0, bits);
+               return buffer.array();
+       }
+
+       public static UUID bytesToUUID(byte[] most, byte[] least) {
+               if (most.length < BYTES_PER_LONG)
+                       most = Arrays.copyOf(most, BYTES_PER_LONG);
+               if (least.length < BYTES_PER_LONG)
+                       least = Arrays.copyOf(least, BYTES_PER_LONG);
+               ByteBuffer buffer = ByteBuffer.allocate(2 * BYTES_PER_LONG);
+               buffer.put(most, 0, BYTES_PER_LONG);
+               buffer.put(least, 0, BYTES_PER_LONG);
+               buffer.flip();
+               return new UUID(buffer.getLong(), buffer.getLong());
+       }
+
+       // public static void main(String[] args) {
+       // UUID uuid = UUID.randomUUID();
+       // System.out.println(uuid);
+       // uuid = bytesToUUID(uuidToBytes(uuid.getMostSignificantBits()),
+       // uuidToBytes(uuid.getLeastSignificantBits()));
+       // System.out.println(uuid);
+       // }
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkContext.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkContext.java
new file mode 100644 (file)
index 0000000..5493dde
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.api.cms.transaction;
+
+import javax.transaction.xa.XAResource;
+
+/**
+ * A minimalistic interface similar to OSGi transaction context in order to
+ * register XA resources.
+ */
+public interface WorkContext {
+       void registerXAResource(XAResource resource, String recoveryId);
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkControl.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkControl.java
new file mode 100644 (file)
index 0000000..de03150
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.api.cms.transaction;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A minimalistic interface inspired by OSGi transaction control in order to
+ * commit units of work externally.
+ */
+public interface WorkControl {
+       <T> T required(Callable<T> work);
+
+       void setRollbackOnly();
+
+       WorkContext getWorkContext();
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkTransaction.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkTransaction.java
new file mode 100644 (file)
index 0000000..39c188d
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.api.cms.transaction;
+
+/**
+ * A minimalistic interface inspired by JTA user transaction in order to commit
+ * units of work externally.
+ */
+public interface WorkTransaction {
+       void begin();
+
+       void commit();
+
+       void rollback();
+
+       boolean isNoTransactionStatus();
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopy.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopy.java
new file mode 100644 (file)
index 0000000..c79423c
--- /dev/null
@@ -0,0 +1,18 @@
+package org.argeo.api.cms.transaction;
+
+import java.util.Map;
+
+public interface WorkingCopy<DATA, ATTR, ID> {
+       void startEditing(DATA user);
+
+       boolean noModifications();
+
+       void cleanUp();
+
+       Map<ID, DATA> getNewData();
+
+       Map<ID, DATA> getDeletedData();
+
+       Map<ID, ATTR> getModifiedData();
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyProcessor.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyProcessor.java
new file mode 100644 (file)
index 0000000..9e7c9e1
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.api.cms.transaction;
+
+public interface WorkingCopyProcessor<WC extends WorkingCopy<?, ?, ?>> {
+       void prepare(WC wc);
+
+       void commit(WC wc);
+
+       void rollback(WC wc);
+       
+       WC newWorkingCopy();
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyXaResource.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyXaResource.java
new file mode 100644 (file)
index 0000000..16b08c2
--- /dev/null
@@ -0,0 +1,138 @@
+package org.argeo.api.cms.transaction;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+/** {@link XAResource} for a user directory being edited. */
+public class WorkingCopyXaResource<WC extends WorkingCopy<?, ?, ?>> implements XAResource {
+       private final WorkingCopyProcessor<WC> processor;
+
+       private Map<Xid, WC> workingCopies = new HashMap<Xid, WC>();
+       private Xid editingXid = null;
+       private int transactionTimeout = 0;
+
+       public WorkingCopyXaResource(WorkingCopyProcessor<WC> processor) {
+               this.processor = processor;
+       }
+
+       @Override
+       public synchronized void start(Xid xid, int flags) throws XAException {
+               if (editingXid != null)
+                       throw new IllegalStateException("Already editing " + editingXid);
+               WC wc = workingCopies.put(xid, processor.newWorkingCopy());
+               if (wc != null)
+                       throw new IllegalStateException("There is already a working copy for " + xid);
+               this.editingXid = xid;
+       }
+
+       @Override
+       public void end(Xid xid, int flags) throws XAException {
+               checkXid(xid);
+       }
+
+       private WC wc(Xid xid) {
+               return workingCopies.get(xid);
+       }
+
+       public synchronized WC wc() {
+               if (editingXid == null)
+                       return null;
+               WC wc = workingCopies.get(editingXid);
+               if (wc == null)
+                       throw new IllegalStateException("No working copy found for " + editingXid);
+               return wc;
+       }
+
+       private synchronized void cleanUp(Xid xid) {
+               WC wc = workingCopies.get(xid);
+               if (wc != null) {
+                       wc.cleanUp();
+                       workingCopies.remove(xid);
+               }
+               editingXid = null;
+       }
+
+       @Override
+       public int prepare(Xid xid) throws XAException {
+               checkXid(xid);
+               WC wc = wc(xid);
+               if (wc.noModifications())
+                       return XA_RDONLY;
+               try {
+                       processor.prepare(wc);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new XAException(XAException.XAER_RMERR);
+               }
+               return XA_OK;
+       }
+
+       @Override
+       public void commit(Xid xid, boolean onePhase) throws XAException {
+               try {
+                       checkXid(xid);
+                       WC wc = wc(xid);
+                       if (wc.noModifications())
+                               return;
+                       if (onePhase)
+                               processor.prepare(wc);
+                       processor.commit(wc);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new XAException(XAException.XAER_RMERR);
+               } finally {
+                       cleanUp(xid);
+               }
+       }
+
+       @Override
+       public void rollback(Xid xid) throws XAException {
+               try {
+                       checkXid(xid);
+                       processor.rollback(wc(xid));
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new XAException(XAException.XAER_RMERR);
+               } finally {
+                       cleanUp(xid);
+               }
+       }
+
+       @Override
+       public void forget(Xid xid) throws XAException {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public boolean isSameRM(XAResource xares) throws XAException {
+               return xares == this;
+       }
+
+       @Override
+       public Xid[] recover(int flag) throws XAException {
+               return new Xid[0];
+       }
+
+       @Override
+       public int getTransactionTimeout() throws XAException {
+               return transactionTimeout;
+       }
+
+       @Override
+       public boolean setTransactionTimeout(int seconds) throws XAException {
+               transactionTimeout = seconds;
+               return true;
+       }
+
+       private void checkXid(Xid xid) throws XAException {
+               if (xid == null)
+                       throw new XAException(XAException.XAER_OUTSIDE);
+               if (!xid.equals(xid))
+                       throw new XAException(XAException.XAER_NOTA);
+       }
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/XAResourceProvider.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/XAResourceProvider.java
new file mode 100644 (file)
index 0000000..904fb5f
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.api.cms.transaction;
+
+import javax.transaction.xa.XAResource;
+
+public interface XAResourceProvider {
+       XAResource getXaResource();
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/package-info.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/package-info.java
new file mode 100644 (file)
index 0000000..bbb9212
--- /dev/null
@@ -0,0 +1,2 @@
+/** Minimalistic and partial XA transaction manager implementation. */
+package org.argeo.api.cms.transaction;
\ No newline at end of file
diff --git a/org.argeo.api.register/.classpath b/org.argeo.api.register/.classpath
new file mode 100644 (file)
index 0000000..4199cd3
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
+               <attributes>
+                       <attribute name="module" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.argeo.api.register/.project b/org.argeo.api.register/.project
new file mode 100644 (file)
index 0000000..a3164c1
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.api.register</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.pde.PluginNature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.argeo.api.register/META-INF/.gitignore b/org.argeo.api.register/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/org.argeo.api.register/bnd.bnd b/org.argeo.api.register/bnd.bnd
new file mode 100644 (file)
index 0000000..bcebf37
--- /dev/null
@@ -0,0 +1,3 @@
+Import-Package:        org.osgi.*;version=0.0.0,\
+!org.apache.commons.logging,\
+*                              
diff --git a/org.argeo.api.register/build.properties b/org.argeo.api.register/build.properties
new file mode 100644 (file)
index 0000000..ae2abc5
--- /dev/null
@@ -0,0 +1 @@
+source.. = src/
\ No newline at end of file
diff --git a/org.argeo.api.register/src/org/argeo/api/register/Component.java b/org.argeo.api.register/src/org/argeo/api/register/Component.java
new file mode 100644 (file)
index 0000000..f4676d9
--- /dev/null
@@ -0,0 +1,333 @@
+package org.argeo.api.register;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * A wrapper for an object, whose dependencies and life cycle can be managed.
+ */
+public class Component<I> implements Supplier<I>, Comparable<Component<?>> {
+
+       private final I instance;
+
+       private final Runnable init;
+       private final Runnable close;
+
+       private final Map<Class<? super I>, PublishedType<? super I>> types;
+       private final Set<Dependency<?>> dependencies;
+       private final Map<String, Object> properties;
+
+       private CompletableFuture<Void> activationStarted = null;
+       private CompletableFuture<Void> activated = null;
+
+       private CompletableFuture<Void> deactivationStarted = null;
+       private CompletableFuture<Void> deactivated = null;
+
+       // internal
+       private Set<Dependency<?>> dependants = new HashSet<>();
+
+       private RankingKey rankingKey;
+
+       Component(ComponentRegister register, I instance, Runnable init, Runnable close, Set<Dependency<?>> dependencies,
+                       Set<Class<? super I>> classes, Map<String, Object> properties) {
+               assert instance != null;
+               assert init != null;
+               assert close != null;
+               assert dependencies != null;
+               assert classes != null;
+
+               this.instance = instance;
+               this.init = init;
+               this.close = close;
+
+               // types
+               Map<Class<? super I>, PublishedType<? super I>> types = new HashMap<>(classes.size());
+               for (Class<? super I> clss : classes) {
+//                     if (!clss.isAssignableFrom(instance.getClass()))
+//                             throw new IllegalArgumentException(
+//                                             "Type " + clss.getName() + " is not compatible with " + instance.getClass().getName());
+                       types.put(clss, new PublishedType<>(this, clss));
+               }
+               this.types = Collections.unmodifiableMap(types);
+
+               // dependencies
+               this.dependencies = Collections.unmodifiableSet(new HashSet<>(dependencies));
+               for (Dependency<?> dependency : this.dependencies) {
+                       dependency.setDependantComponent(this);
+               }
+
+               // deactivated by default
+               deactivated = CompletableFuture.completedFuture(null);
+               deactivationStarted = CompletableFuture.completedFuture(null);
+
+               // TODO check whether context is active, so that we start right away
+               prepareNextActivation();
+
+               long serviceId = register.register(this);
+               Map<String, Object> props = new HashMap<>(properties);
+               props.put(RankingKey.SERVICE_ID, serviceId);
+               this.properties = Collections.unmodifiableMap(props);
+               rankingKey = new RankingKey(properties);
+       }
+
+       private void prepareNextActivation() {
+               activationStarted = new CompletableFuture<Void>();
+               activated = activationStarted //
+                               .thenComposeAsync(this::dependenciesActivated) //
+                               .thenRun(this.init) //
+                               .thenRun(() -> prepareNextDeactivation());
+       }
+
+       private void prepareNextDeactivation() {
+               deactivationStarted = new CompletableFuture<Void>();
+               deactivated = deactivationStarted //
+                               .thenComposeAsync(this::dependantsDeactivated) //
+                               .thenRun(this.close) //
+                               .thenRun(() -> prepareNextActivation());
+       }
+
+       CompletableFuture<Void> getActivated() {
+               return activated;
+       }
+
+       CompletableFuture<Void> getDeactivated() {
+               return deactivated;
+       }
+
+       void startActivating() {
+               if (activated.isDone() || activationStarted.isDone())
+                       return;
+               activationStarted.complete(null);
+       }
+
+       void startDeactivating() {
+               if (deactivated.isDone() || deactivationStarted.isDone())
+                       return;
+               deactivationStarted.complete(null);
+       }
+
+       CompletableFuture<Void> dependenciesActivated(Void v) {
+               Set<CompletableFuture<?>> constraints = new HashSet<>(this.dependencies.size());
+               for (Dependency<?> dependency : this.dependencies) {
+                       CompletableFuture<Void> dependencyActivated = dependency.publisherActivated() //
+                                       .thenCompose(dependency::set);
+                       constraints.add(dependencyActivated);
+               }
+               return CompletableFuture.allOf(constraints.toArray(new CompletableFuture[constraints.size()]));
+       }
+
+       CompletableFuture<Void> dependantsDeactivated(Void v) {
+               Set<CompletableFuture<?>> constraints = new HashSet<>(this.dependants.size());
+               for (Dependency<?> dependant : this.dependants) {
+                       CompletableFuture<Void> dependantDeactivated = dependant.dependantDeactivated() //
+                                       .thenCompose(dependant::unset);
+                       constraints.add(dependantDeactivated);
+               }
+               CompletableFuture<Void> dependantsDeactivated = CompletableFuture
+                               .allOf(constraints.toArray(new CompletableFuture[constraints.size()]));
+               return dependantsDeactivated;
+
+       }
+
+       void addDependant(Dependency<?> dependant) {
+               dependants.add(dependant);
+       }
+
+       @Override
+       public I get() {
+               return instance;
+       }
+
+       @SuppressWarnings("unchecked")
+       public <T> PublishedType<T> getType(Class<T> clss) {
+               if (!types.containsKey(clss))
+                       throw new IllegalArgumentException(clss.getName() + " is not a type published by this component");
+               return (PublishedType<T>) types.get(clss);
+       }
+
+       public <T> boolean isPublishedType(Class<T> clss) {
+               return types.containsKey(clss);
+       }
+
+       public Map<String, Object> getProperties() {
+               return properties;
+       }
+
+       @Override
+       public int compareTo(Component<?> o) {
+               return rankingKey.compareTo(rankingKey);
+       }
+
+       @Override
+       public int hashCode() {
+               Long serviceId = (Long) properties.get(RankingKey.SERVICE_ID);
+               if (serviceId != null)
+                       return serviceId.intValue();
+               else
+                       return super.hashCode();
+       }
+
+       @Override
+       public String toString() {
+               List<String> classes = new ArrayList<>();
+               for (Class<?> clss : types.keySet()) {
+                       classes.add(clss.getName());
+               }
+               return "Component " + classes + " " + properties + "";
+       }
+
+       /** A type which has been explicitly exposed by a component. */
+       public static class PublishedType<T> {
+               private Component<? extends T> component;
+               private Class<T> clss;
+
+               private CompletableFuture<T> value;
+
+               public PublishedType(Component<? extends T> component, Class<T> clss) {
+                       this.clss = clss;
+                       this.component = component;
+                       value = CompletableFuture.completedFuture((T) component.instance);
+               }
+
+               public Component<?> getPublisher() {
+                       return component;
+               }
+
+               public Class<T> getType() {
+                       return clss;
+               }
+
+               public CompletionStage<T> getValue() {
+                       return value.minimalCompletionStage();
+               }
+       }
+
+       /** Builds a {@link Component}. */
+       public static class Builder<I> implements Supplier<I> {
+               private final I instance;
+
+               private Runnable init;
+               private Runnable close;
+
+               private Set<Dependency<?>> dependencies = new HashSet<>();
+               private Set<Class<? super I>> types = new HashSet<>();
+               private final Map<String, Object> properties = new HashMap<>();
+
+               public Builder(I instance) {
+                       this.instance = instance;
+               }
+
+               public Component<I> build(ComponentRegister register) {
+                       // default values
+                       if (types.isEmpty()) {
+                               types.add(getInstanceClass());
+                       }
+
+                       if (init == null)
+                               init = () -> {
+                               };
+                       if (close == null)
+                               close = () -> {
+                               };
+
+                       // instantiation
+                       Component<I> component = new Component<I>(register, instance, init, close, dependencies, types, properties);
+                       for (Dependency<?> dependency : dependencies) {
+                               dependency.type.getPublisher().addDependant(dependency);
+                       }
+                       return component;
+               }
+
+               public Builder<I> addType(Class<? super I> clss) {
+                       types.add(clss);
+                       return this;
+               }
+
+               public Builder<I> addActivation(Runnable init) {
+                       if (this.init != null)
+                               throw new IllegalArgumentException("init method is already set");
+                       this.init = init;
+                       return this;
+               }
+
+               public Builder<I> addDeactivation(Runnable close) {
+                       if (this.close != null)
+                               throw new IllegalArgumentException("close method is already set");
+                       this.close = close;
+                       return this;
+               }
+
+               public <D> Builder<I> addDependency(PublishedType<D> type, Consumer<D> set, Consumer<D> unset) {
+                       dependencies.add(new Dependency<D>(type, set, unset));
+                       return this;
+               }
+
+               public void addProperty(String key, Object value) {
+                       if (properties.containsKey(key))
+                               throw new IllegalStateException("Key " + key + " is already set.");
+                       properties.put(key, value);
+               }
+
+               @Override
+               public I get() {
+                       return instance;
+               }
+
+               @SuppressWarnings("unchecked")
+               private Class<I> getInstanceClass() {
+                       return (Class<I>) instance.getClass();
+               }
+
+       }
+
+       static class Dependency<D> {
+               private PublishedType<D> type;
+               private Consumer<D> set;
+               private Consumer<D> unset;
+
+               // live
+               Component<?> dependantComponent;
+               CompletableFuture<Void> setStage;
+               CompletableFuture<Void> unsetStage;
+
+               public Dependency(PublishedType<D> types, Consumer<D> set, Consumer<D> unset) {
+                       super();
+                       this.type = types;
+                       this.set = set != null ? set : t -> {
+                       };
+                       this.unset = unset != null ? unset : t -> {
+                       };
+               }
+
+               // live
+               void setDependantComponent(Component<?> component) {
+                       this.dependantComponent = component;
+               }
+
+               CompletableFuture<Void> publisherActivated() {
+                       return type.getPublisher().activated.copy();
+               }
+
+               CompletableFuture<Void> dependantDeactivated() {
+                       return dependantComponent.deactivated.copy();
+               }
+
+               CompletableFuture<Void> set(Void v) {
+                       return type.value.thenAccept(set);
+               }
+
+               CompletableFuture<Void> unset(Void v) {
+                       return type.value.thenAccept(unset);
+               }
+
+       }
+}
diff --git a/org.argeo.api.register/src/org/argeo/api/register/ComponentRegister.java b/org.argeo.api.register/src/org/argeo/api/register/ComponentRegister.java
new file mode 100644 (file)
index 0000000..1bb9036
--- /dev/null
@@ -0,0 +1,43 @@
+package org.argeo.api.register;
+
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.function.Predicate;
+
+/** A register of components which can coordinate their activation. */
+public interface ComponentRegister {
+       long register(Component<?> component);
+
+       <T> SortedSet<Component<? extends T>> find(Class<T> clss, Predicate<Map<String, Object>> filter);
+
+       default <T> Component.PublishedType<T> getSingleton(Class<T> type) {
+               SortedSet<Component<? extends T>> found = find(type, null);
+               if (found.size() == 0)
+                       throw new IllegalStateException("No component found for " + type);
+               return found.first().getType(type);
+       }
+
+       default <T> T getObject(Class<T> clss) {
+               SortedSet<Component<? extends T>> found = find(clss, null);
+               if (found.size() == 0)
+                       return null;
+               return found.first().get();
+       }
+
+       Component<?> get(Object instance);
+
+//     default <T> PublishedType<T> getType(Class<T> clss) {
+//             SortedSet<Component<? extends T>> components = find(clss, null);
+//             if (components.size() == 0)
+//                     return null;
+//             return components.first().getType(clss);
+//     }
+
+       void activate();
+
+       void deactivate();
+
+       boolean isActive();
+
+       void clear();
+}
diff --git a/org.argeo.api.register/src/org/argeo/api/register/RankingKey.java b/org.argeo.api.register/src/org/argeo/api/register/RankingKey.java
new file mode 100644 (file)
index 0000000..3886afe
--- /dev/null
@@ -0,0 +1,105 @@
+package org.argeo.api.register;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Key used to classify and filter available components.
+ */
+public class RankingKey implements Comparable<RankingKey> {
+       public final static String SERVICE_PID = "service.pid";
+       public final static String SERVICE_ID = "service.id";
+       public final static String SERVICE_RANKING = "service.ranking";
+
+       private String pid;
+       private Integer ranking = 0;
+       private Long id = 0l;
+
+       public RankingKey(String pid, Integer ranking, Long id) {
+               super();
+               this.pid = pid;
+               this.ranking = ranking;
+               this.id = id;
+       }
+
+       public RankingKey(Map<String, Object> properties) {
+               this.pid = properties.containsKey(SERVICE_PID) ? properties.get(SERVICE_PID).toString() : null;
+               this.ranking = properties.containsKey(SERVICE_RANKING)
+                               ? Integer.parseInt(properties.get(SERVICE_RANKING).toString())
+                               : 0;
+               this.id = properties.containsKey(SERVICE_ID) ? (Long) properties.get(SERVICE_ID) : null;
+       }
+
+       @Override
+       public int hashCode() {
+               Integer result = 0;
+               if (pid != null)
+                       result = +pid.hashCode();
+               if (ranking != null)
+                       result = +ranking;
+               return result;
+       }
+
+       @Override
+       protected Object clone() throws CloneNotSupportedException {
+               return new RankingKey(pid, ranking, id);
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder sb = new StringBuilder("");
+               if (pid != null)
+                       sb.append(pid);
+               if (ranking != null && ranking != 0)
+                       sb.append(' ').append(ranking);
+               return sb.toString();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof RankingKey))
+                       return false;
+               RankingKey other = (RankingKey) obj;
+               return Objects.equals(pid, other.pid) && Objects.equals(ranking, other.ranking) && Objects.equals(id, other.id);
+       }
+
+       @Override
+       public int compareTo(RankingKey o) {
+               if (pid != null && o.pid != null) {
+                       if (pid.equals(o.pid)) {
+                               if (ranking.equals(o.ranking))
+                                       if (id != null && o.id != null)
+                                               return id.compareTo(o.id);
+                                       else
+                                               return 0;
+                               else
+                                       return ranking.compareTo(o.ranking);
+                       } else {
+                               return pid.compareTo(o.pid);
+                       }
+
+               } else {
+               }
+               return -1;
+       }
+
+       public String getPid() {
+               return pid;
+       }
+
+       public Integer getRanking() {
+               return ranking;
+       }
+
+       public Long getId() {
+               return id;
+       }
+
+       public static RankingKey minPid(String pid) {
+               return new RankingKey(pid, Integer.MIN_VALUE, null);
+       }
+
+       public static RankingKey maxPid(String pid) {
+               return new RankingKey(pid, Integer.MAX_VALUE, null);
+       }
+}
diff --git a/org.argeo.api.register/src/org/argeo/api/register/SimpleRegister.java b/org.argeo.api.register/src/org/argeo/api/register/SimpleRegister.java
new file mode 100644 (file)
index 0000000..9ed7e76
--- /dev/null
@@ -0,0 +1,124 @@
+package org.argeo.api.register;
+
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Predicate;
+
+/** A minimal component register. */
+public class SimpleRegister implements ComponentRegister {
+       private final AtomicBoolean started = new AtomicBoolean(false);
+       private final IdentityHashMap<Object, Component<?>> components = new IdentityHashMap<>();
+       private final AtomicLong nextServiceId = new AtomicLong(0l);
+
+       @Override
+       public long register(Component<?> component) {
+               return registerComponent(component);
+       }
+
+       @SuppressWarnings({ "unchecked" })
+       @Override
+       public synchronized <T> SortedSet<Component<? extends T>> find(Class<T> clss,
+                       Predicate<Map<String, Object>> filter) {
+               SortedSet<Component<? extends T>> result = new TreeSet<>();
+               instances: for (Object instance : components.keySet()) {
+                       if (!clss.isAssignableFrom(instance.getClass()))
+                               continue instances;
+                       Component<? extends T> component = (Component<? extends T>) components.get(instance);
+
+                       if (component.isPublishedType(clss)) {
+                               if (filter != null) {
+                                       filter.test(component.getProperties());
+                               }
+                               result.add(component);
+                       }
+               }
+               if (result.isEmpty())
+                       return null;
+               return result;
+
+       }
+
+       synchronized long registerComponent(Component<?> component) {
+               if (started.get()) // TODO make it really dynamic
+                       throw new IllegalStateException("Already activated");
+               if (components.containsKey(component.get()))
+                       throw new IllegalArgumentException("Already registered as component");
+               components.put(component.get(), component);
+               return nextServiceId.incrementAndGet();
+       }
+
+       @Override
+       public synchronized Component<?> get(Object instance) {
+               if (!components.containsKey(instance))
+                       throw new IllegalArgumentException("Not registered as component");
+               return components.get(instance);
+       }
+
+       @Override
+       public synchronized void activate() {
+               if (started.get())
+                       throw new IllegalStateException("Already activated");
+               Set<CompletableFuture<?>> constraints = new HashSet<>();
+               for (Component<?> component : components.values()) {
+                       component.startActivating();
+                       constraints.add(component.getActivated());
+               }
+
+               // wait
+               try {
+                       CompletableFuture.allOf(constraints.toArray(new CompletableFuture[0])).thenRun(() -> started.set(true))
+                                       .get();
+               } catch (InterruptedException e) {
+                       throw new RuntimeException("Register activation has been interrupted", e);
+               } catch (ExecutionException e) {
+                       if (RuntimeException.class.isAssignableFrom(e.getCause().getClass())) {
+                               throw (RuntimeException) e.getCause();
+                       } else {
+                               throw new IllegalStateException("Cannot activate register", e.getCause());
+                       }
+               }
+       }
+
+       @Override
+       public synchronized void deactivate() {
+               if (!started.get())
+                       throw new IllegalStateException("Not activated");
+               Set<CompletableFuture<?>> constraints = new HashSet<>();
+               for (Component<?> component : components.values()) {
+                       component.startDeactivating();
+                       constraints.add(component.getDeactivated());
+               }
+
+               // wait
+               try {
+                       CompletableFuture.allOf(constraints.toArray(new CompletableFuture[0])).thenRun(() -> started.set(false))
+                                       .get();
+               } catch (InterruptedException e) {
+                       throw new RuntimeException("Register deactivation has been interrupted", e);
+               } catch (ExecutionException e) {
+                       if (RuntimeException.class.isAssignableFrom(e.getCause().getClass())) {
+                               throw (RuntimeException) e.getCause();
+                       } else {
+                               throw new IllegalStateException("Cannot deactivate register", e.getCause());
+                       }
+               }
+       }
+
+       @Override
+       public synchronized boolean isActive() {
+               return started.get();
+       }
+
+       @Override
+       public synchronized void clear() {
+               components.clear();
+       }
+}
index 6dbd403dd506468341c42b09f13e419619740413..fd158fb8315db647b8d0b07e7790d1ec57aa2b3f 100644 (file)
@@ -143,9 +143,7 @@ public class ConcurrentTimeUuidState implements UuidFactory.TimeUuidState {
        @Override
        public long getMostSignificantBits() {
                long timestamp = useTimestamp();
-               long mostSig = UuidFactory.MOST_SIG_VERSION1 | ((timestamp & 0xFFFFFFFFL) << 32) // time_low
-                               | (((timestamp >> 32) & 0xFFFFL) << 16) // time_mid
-                               | ((timestamp >> 48) & 0x0FFFL);// time_hi_and_version
+               long mostSig = TimeUuid.toMostSignificantBits(timestamp);
                return mostSig;
        }
 
index 2276cd26831976344acb80e53b708aca902da854..2e0587d12748128445ee3b81b64439fa8b6a59f2 100644 (file)
@@ -76,4 +76,23 @@ public class TimeUuid extends TypedUuid {
                Duration duration = Duration.between(TimeUuid.TIMESTAMP_ZERO, instant);
                return durationToTimestamp(duration);
        }
+
+       /**
+        * Crate a time UUID with this instant as timestamp and clock and node id set to
+        * zero.
+        */
+       public static UUID fromInstant(Instant instant) {
+               long timestamp = instantToTimestamp(instant);
+               long mostSig = toMostSignificantBits(timestamp);
+               UUID uuid = new UUID(mostSig, UuidFactory.LEAST_SIG_RFC4122_VARIANT);
+               return uuid;
+       }
+
+       /** Convert timestamp in UUID format to most significant bits of a time UUID. */
+       static long toMostSignificantBits(long timestamp) {
+               long mostSig = UuidFactory.MOST_SIG_VERSION1 | ((timestamp & 0xFFFFFFFFL) << 32) // time_low
+                               | (((timestamp >> 32) & 0xFFFFL) << 16) // time_mid
+                               | ((timestamp >> 48) & 0x0FFFL);// time_hi_and_version
+               return mostSig;
+       }
 }
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..07d35f219a83240493df739c78e4f6234a9743c3 100644 (file)
@@ -0,0 +1,58 @@
+Main-Class: org.argeo.cms.cli.ArgeoCli
+
+Class-Path: \
+org.argeo.api.acr.2.3.jar \
+org.argeo.api.cli.2.3.jar \
+org.argeo.api.cms.2.3.jar \
+org.argeo.api.uuid.2.3.jar \
+org.argeo.cms.2.3.jar \
+org.argeo.cms.ee.2.3.jar \
+../osgi/equinox/org.argeo.cms/org.argeo.cms.lib.equinox.2.3.jar \
+org.argeo.cms.lib.jetty.2.3.jar \
+org.argeo.cms.lib.sshd.2.3.jar \
+org.argeo.cms.ux.2.3.jar \
+org.argeo.init.2.3.jar \
+org.argeo.util.2.3.jar \
+../org.argeo.tp/com.fasterxml.jackson.core.jackson-annotations.2.13.jar \
+../org.argeo.tp/com.fasterxml.jackson.core.jackson-core.2.13.jar \
+../org.argeo.tp/com.fasterxml.jackson.core.jackson-databind.2.13.jar \
+../org.argeo.tp/com.googlecode.javaewah.JavaEWAH.1.1.jar \
+../org.argeo.tp/de.thjom.java.systemd.2.1.jar \
+../org.argeo.tp/javax.servlet.4.0.jar \
+../org.argeo.tp/javax.websocket.1.1.jar \
+../org.argeo.tp/org.apache.batik.1.16.jar \
+../org.argeo.tp/org.apache.batik.constants.1.16.jar \
+../org.argeo.tp/org.apache.batik.css.1.16.jar \
+../org.argeo.tp/org.apache.batik.i18n.1.16.jar \
+../org.argeo.tp/org.apache.batik.util.1.16.jar \
+../org.argeo.tp/org.apache.commons.cli.1.5.jar \
+../org.argeo.tp/org.apache.commons.fileupload.1.4.jar \
+../org.argeo.tp/org.apache.commons.io.2.11.jar \
+../org.argeo.tp/org.apache.httpcomponents.httpclient.4.5.jar \
+../org.argeo.tp/org.apache.httpcomponents.httpcore.4.4.jar \
+../org.argeo.tp/org.apache.httpcomponents.httpmime.4.5.jar \
+../org.argeo.tp/org.apache.xalan.2.7.jar \
+../org.argeo.tp/org.apache.xerces.2.12.jar \
+../org.argeo.tp/org.apache.xmlgraphics.2.7.jar \
+../org.argeo.tp/org.apache.xml.resolver.1.2.jar \
+../org.argeo.tp/org.argeo.ext.slf4j.2.3.jar \
+../org.argeo.tp/org.eclipse.jgit.6.3.jar \
+../org.argeo.tp/org.freeedesktop.dbus.4.2.jar \
+../org.argeo.tp/org.slf4j.api.1.7.jar \
+../org.argeo.tp/org.slf4j.commons.logging.1.7.jar \
+../org.argeo.tp/org.w3c.css.sac.1.3.jar \
+../org.argeo.tp/org.w3c.dom.smil.1.0.jar \
+../org.argeo.tp/org.w3c.dom.svg.1.1.jar \
+../org.argeo.tp.crypto/bcmail.1.72.jar \
+../org.argeo.tp.crypto/bcpg.1.72.jar \
+../org.argeo.tp.crypto/bcpkix.1.72.jar \
+../org.argeo.tp.crypto/bcprov.1.72.jar \
+../org.argeo.tp.crypto/bcutil.1.72.jar \
+../org.argeo.tp.crypto/net.i2p.crypto.eddsa.0.3.jar \
+../org.argeo.tp.crypto/org.apache.sshd.2.9.jar \
+../org.argeo.tp.crypto/org.apache.sshd.cli.2.9.jar \
+../org.argeo.tp.crypto/org.apache.sshd.git.2.9.jar \
+../org.argeo.tp.crypto/org.apache.sshd.putty.2.9.jar \
+../org.argeo.tp.crypto/org.apache.sshd.scp.2.9.jar \
+../org.argeo.tp.crypto/org.apache.sshd.sftp.2.9.jar \
+../org.argeo.tp.crypto/org.apache.tomcat.jni.9.0.jar \
index 1dd57f3df9083ecba86824789d5418c1b6f99b66..b55f9d6ade5bdcbd0b6d3a2fa501020712bca56e 100644 (file)
@@ -15,6 +15,7 @@ public class ArgeoCli extends CommandsCli {
                                Option.builder("D").hasArgs().argName("property=value").desc("use value for given property").build());
 
                // common
+               addCommandsCli(new CmsCommands("cms"));
                addCommandsCli(new SshCli("ssh"));
                addCommandsCli(new PosixCommands("posix"));
                addCommandsCli(new FsCommands("fs"));
@@ -22,7 +23,11 @@ public class ArgeoCli extends CommandsCli {
 
        @Override
        public String getDescription() {
-               return "Argeo utilities";
+               return "Argeo CMS utilities";
+       }
+
+       public static void main(String[] args) {
+               mainImpl(new ArgeoCli("argeo"), args);
        }
 
 }
diff --git a/org.argeo.cms.cli/src/org/argeo/cms/cli/CmsCommands.java b/org.argeo.cms.cli/src/org/argeo/cms/cli/CmsCommands.java
new file mode 100644 (file)
index 0000000..50977d1
--- /dev/null
@@ -0,0 +1,128 @@
+package org.argeo.cms.cli;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.argeo.api.cli.CommandsCli;
+import org.argeo.api.cli.DescribedCommand;
+import org.argeo.cms.client.CmsClient;
+import org.argeo.cms.client.WebSocketPing;
+
+/** Commands dealing with CMS. */
+public class CmsCommands extends CommandsCli {
+       final static Option connectOption = Option.builder().option("c").longOpt("connect").desc("server to connect to")
+                       .hasArg(true).build();
+
+       public CmsCommands(String commandName) {
+               super(commandName);
+               addCommand("ping", new Ping());
+               addCommand("get", new Get());
+               addCommand("status", new Status());
+               addCommand("event", new EventCommands("event"));
+       }
+
+       @Override
+       public String getDescription() {
+               return "Utilities related to an Argeo CMS";
+       }
+
+       class Ping implements DescribedCommand<Void> {
+               @Override
+               public Options getOptions() {
+                       Options options = new Options();
+                       options.addOption(connectOption);
+                       return options;
+               }
+
+               @Override
+               public Void apply(List<String> t) {
+                       CommandLine line = toCommandLine(t);
+                       String uriArg = line.getOptionValue(connectOption);
+                       // TODO make it more robust (trailing /, etc.)
+                       URI uri = URI.create(uriArg);
+                       if ("".equals(uri.getPath())) {
+                               uri = URI.create(uri.toString() + "/cms/status/ping");
+                       }
+                       new WebSocketPing(uri).run();
+                       return null;
+               }
+
+               @Override
+               public String getUsage() {
+                       return "[ws|wss]://host:port/";
+               }
+
+               @Override
+               public String getDescription() {
+                       return "Test whether an Argeo CMS is available, without auhtentication";
+               }
+
+       }
+
+       class Get implements DescribedCommand<String> {
+
+               @Override
+               public Options getOptions() {
+                       Options options = new Options();
+                       options.addOption(connectOption);
+                       return options;
+               }
+
+               @Override
+               public String apply(List<String> t) {
+                       CommandLine line = toCommandLine(t);
+                       List<String> remaining = line.getArgList();
+                       String additionalUri = null;
+                       if (remaining.size() != 0) {
+                               additionalUri = remaining.get(0);
+                       }
+
+                       String connectUri = line.getOptionValue(connectOption);
+                       CmsClient cmsClient = new CmsClient(URI.create(connectUri));
+                       return additionalUri != null ? cmsClient.getAsString(URI.create(additionalUri)) : cmsClient.getAsString();
+               }
+
+               @Override
+               public String getUsage() {
+                       return "[URI]";
+               }
+
+               @Override
+               public String getDescription() {
+                       return "Retrieve this URI as a string";
+               }
+
+       }
+
+       class Status implements DescribedCommand<String> {
+
+               @Override
+               public Options getOptions() {
+                       Options options = new Options();
+                       options.addOption(connectOption);
+                       return options;
+               }
+
+               @Override
+               public String apply(List<String> t) {
+                       CommandLine line = toCommandLine(t);
+                       String connectUri = line.getOptionValue(connectOption);
+                       CmsClient cmsClient = new CmsClient(URI.create(connectUri));
+                       return cmsClient.getAsString(URI.create("/cms/status"));
+               }
+
+               @Override
+               public String getUsage() {
+                       return "[URI]";
+               }
+
+               @Override
+               public String getDescription() {
+                       return "Retrieve the CMS status as a string";
+               }
+
+       }
+}
diff --git a/org.argeo.cms.cli/src/org/argeo/cms/cli/EventCommands.java b/org.argeo.cms.cli/src/org/argeo/cms/cli/EventCommands.java
new file mode 100644 (file)
index 0000000..009ad45
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.cms.cli;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.argeo.api.cli.CommandArgsException;
+import org.argeo.api.cli.CommandsCli;
+import org.argeo.api.cli.DescribedCommand;
+import org.argeo.cms.client.WebSocketEventClient;
+
+/** Commands dealing with CMS events. */
+public class EventCommands extends CommandsCli {
+       public EventCommands(String commandName) {
+               super(commandName);
+               addCommand("listen", new EventListent());
+       }
+
+       @Override
+       public String getDescription() {
+               return "Utilities related to an Argeo CMS";
+       }
+
+       class EventListent implements DescribedCommand<Void> {
+
+               @Override
+               public Options getOptions() {
+                       Options options = new Options();
+                       options.addOption(CmsCommands.connectOption);
+                       return options;
+               }
+
+               @Override
+               public Void apply(List<String> t) {
+                       CommandLine line = toCommandLine(t);
+                       List<String> remaining = line.getArgList();
+                       if (remaining.size() == 0) {
+                               throw new CommandArgsException("There must be at least one argument");
+                       }
+                       String topic = remaining.get(0);
+
+                       String uriArg = line.getOptionValue(CmsCommands.connectOption);
+                       // TODO make it more robust (trailing /, etc.)
+                       URI uri = URI.create(uriArg);
+                       if ("".equals(uri.getPath())) {
+                               uri = URI.create(uri.toString() + "/cms/status/event/" + topic);
+                       }
+                       new WebSocketEventClient(uri).run();
+                       return null;
+               }
+
+               @Override
+               public String getUsage() {
+                       return "TOPIC";
+               }
+
+               @Override
+               public String getDescription() {
+                       return "Listen to events on a topic";
+               }
+
+       }
+}
index 37e6c5fbaf1b1622a06b07c3eadd027621abb4a2..b6e9bfd059c8985c1a696e9814b1564ebc7ee05e 100644 (file)
@@ -4,6 +4,6 @@
    <service>
       <provide interface="com.sun.net.httpserver.HttpHandler"/>
    </service>
-   <property name="context.path" type="String" value="/cms/status"/>
+   <property name="context.path" type="String" value="/cms/status/"/>
    <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
 </scr:component>
index 08ce1365c513203b391e2a3736acd727fa3091ea..f09995c002a580a5684daf890e871e04148b319d 100644 (file)
@@ -1,5 +1,4 @@
 Import-Package:\
-org.argeo.util.http,\
 org.osgi.service.http;version=0.0.0,\
 org.osgi.service.http.whiteboard;version=0.0.0,\
 org.osgi.framework.namespace;version=0.0.0,\
index 205699464f43aab954127acb2cb82faa211f676d..672722946327febd0cf8b1c617b0a25c66b0bac0 100644 (file)
@@ -6,7 +6,7 @@ import java.io.Writer;
 import javax.servlet.http.HttpServletResponse;
 
 import org.argeo.api.cms.CmsLog;
-import org.argeo.util.ExceptionsChain;
+import org.argeo.cms.util.ExceptionsChain;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
index 0628eae3646de9244afab61212b943bf318233ff..d18637d3f805ff9e9055bcb4b5f23192d7ac6e31 100644 (file)
@@ -15,7 +15,7 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.argeo.api.cms.CmsAuth;
 import org.argeo.api.cms.CmsSessionId;
-import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.auth.RemoteAuthCallback;
 import org.argeo.cms.auth.RemoteAuthCallbackHandler;
 import org.argeo.cms.servlet.ServletHttpRequest;
index 983202ad2147b7d30908a3ae09a4cc8cd6ed35d4..c355ecd8d93eb8f570a2f22476a4dc64fae359b8 100644 (file)
@@ -15,13 +15,13 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.argeo.api.acr.ldap.NamingUtils;
 import org.argeo.api.cms.CmsAuth;
-import org.argeo.cms.CmsUserManager;
+import org.argeo.api.cms.directory.CmsUserManager;
 import org.argeo.cms.auth.RemoteAuthCallback;
 import org.argeo.cms.auth.RemoteAuthCallbackHandler;
 import org.argeo.cms.servlet.ServletHttpRequest;
 import org.argeo.cms.servlet.ServletHttpResponse;
-import org.argeo.util.naming.NamingUtils;
 import org.osgi.service.useradmin.Authorization;
 
 import com.fasterxml.jackson.core.JsonGenerator;
index 6a5208730fdd4af179afbc1de536367629365b28..d3c0eb5402d45b5e25bb4b0bfe62d4b782f27d5b 100644 (file)
@@ -2,11 +2,8 @@ package org.argeo.cms.servlet;
 
 import java.io.IOException;
 import java.net.URL;
-import java.net.http.HttpHeaders;
-import java.security.PrivilegedAction;
 import java.util.Map;
 
-import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 import javax.servlet.http.HttpServletRequest;
@@ -19,7 +16,6 @@ import org.argeo.cms.auth.RemoteAuthRequest;
 import org.argeo.cms.auth.RemoteAuthResponse;
 import org.argeo.cms.auth.RemoteAuthUtils;
 import org.argeo.cms.servlet.internal.HttpUtils;
-import org.argeo.util.http.HttpHeader;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.service.http.context.ServletContextHelper;
index de47365cac754ff411272f257be217f0e895fb0a..0c600e54b13b2f1db19a13c31af1cc8aab515c72 100644 (file)
@@ -15,8 +15,13 @@ public class ServletHttpResponse implements RemoteAuthResponse {
        }
 
        @Override
-       public void setHeader(String keys, String value) {
-               response.setHeader(keys, value);
+       public void setHeader(String headerName, String value) {
+               response.setHeader(headerName, value);
+       }
+
+       @Override
+       public void addHeader(String headerName, String value) {
+               response.addHeader(headerName, value);
        }
 
 }
diff --git a/org.argeo.cms.ee/src/org/argeo/cms/servlet/ServletUtils.java b/org.argeo.cms.ee/src/org/argeo/cms/servlet/ServletUtils.java
new file mode 100644 (file)
index 0000000..072417a
--- /dev/null
@@ -0,0 +1,52 @@
+package org.argeo.cms.servlet;
+
+import static org.argeo.cms.http.HttpHeader.VIA;
+import static org.argeo.cms.http.HttpHeader.X_FORWARDED_HOST;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+/** Servlet utilities. */
+public class ServletUtils {
+
+       /**
+        * The base URL for this query (without any path component (not even an ending
+        * '/'), taking into account reverse proxies.
+        */
+       public static StringBuilder getRequestUrlBase(HttpServletRequest req) {
+               List<String> viaHosts = new ArrayList<>();
+               for (Enumeration<String> it = req.getHeaders(VIA.getHeaderName()); it.hasMoreElements();) {
+                       String[] arr = it.nextElement().split(" ");
+                       viaHosts.add(arr[1]);
+               }
+
+               String outerHost = viaHosts.isEmpty() ? null : viaHosts.get(0);
+               if (outerHost == null) {
+                       // Try non-standard header
+                       String forwardedHost = req.getHeader(X_FORWARDED_HOST.getHeaderName());
+                       if (forwardedHost != null) {
+                               String[] arr = forwardedHost.split(",");
+                               outerHost = arr[0];
+                       }
+               }
+
+               URI requestUrl = URI.create(req.getRequestURL().toString());
+
+               boolean isReverseProxy = outerHost != null && !outerHost.equals(requestUrl.getHost());
+               if (isReverseProxy) {
+                       String protocol = req.isSecure() ? "https" : "http";
+                       return new StringBuilder(protocol + "://" + outerHost);
+               } else {
+                       return new StringBuilder(requestUrl.getScheme() + "://" + requestUrl.getHost()
+                                       + (requestUrl.getPort() > 0 ? ":" + requestUrl.getPort() : ""));
+               }
+       }
+
+       /** singleton */
+       private ServletUtils() {
+       }
+}
index b2f73944985e23210f267475f58193683b5829ad..63d59a88d0510cf9565ccac177bb1608e96ca68e 100644 (file)
@@ -15,6 +15,10 @@ import com.sun.net.httpserver.HttpContext;
 import com.sun.net.httpserver.HttpHandler;
 import com.sun.net.httpserver.HttpPrincipal;
 
+/**
+ * An {@link HttpServlet} which integrates an {@link HttpContext} and its
+ * {@link Authenticator} in a servlet container.
+ */
 public class HttpContextServlet extends HttpServlet {
        private static final long serialVersionUID = 2321612280413662738L;
 
index 5a29fbe8401ece3e9c209239b8eeb27fd1428251..f5e9c03945f4877c62f36369d264d75ed5bd1aea 100644 (file)
@@ -18,7 +18,8 @@ import com.sun.net.httpserver.HttpContext;
 import com.sun.net.httpserver.HttpPrincipal;
 import com.sun.net.httpserver.HttpsExchange;
 
-public class ServletHttpExchange extends HttpsExchange {
+/** Integrates {@link HttpsExchange} in a servlet container. */
+class ServletHttpExchange extends HttpsExchange {
        private final HttpContext httpContext;
        private final HttpServletRequest httpServletRequest;
        private final HttpServletResponse httpServletResponse;
index c762b67ecc36a610b3e24508861cdcf4655c064b..2b2ffcb10f084ff397a38df47354a72bb7dc32cd 100644 (file)
@@ -12,9 +12,9 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.commons.io.IOUtils;
+import org.argeo.cms.osgi.FilterRequirement;
 import org.argeo.cms.osgi.PublishNamespace;
-import org.argeo.osgi.util.FilterRequirement;
+import org.argeo.cms.util.StreamUtils;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
@@ -126,7 +126,7 @@ public class PkgServlet extends HttpServlet {
                }
 
                try (InputStream in = internalURL.openStream()) {
-                       IOUtils.copy(in, resp.getOutputStream());
+                       StreamUtils.copy(in, resp.getOutputStream());
                }
        }
 
index c71c862d65c1cf195a8d0a7399a1ecfbd9a33f43..defc59efcadf1e49926f373fe97781eecdf4c89e 100644 (file)
@@ -1,9 +1,11 @@
 package org.argeo.cms.websocket.server;
 
 import java.io.IOException;
+import java.nio.channels.ClosedChannelException;
 import java.util.Map;
 
 import javax.websocket.OnClose;
+import javax.websocket.OnError;
 import javax.websocket.OnOpen;
 import javax.websocket.RemoteEndpoint;
 import javax.websocket.Session;
@@ -12,11 +14,13 @@ import javax.websocket.server.ServerEndpoint;
 
 import org.argeo.api.cms.CmsEventBus;
 import org.argeo.api.cms.CmsEventSubscriber;
+import org.argeo.api.cms.CmsLog;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 
-@ServerEndpoint(value = "/event/{topic}", configurator = CmsWebSocketConfigurator.class)
+@ServerEndpoint(value = "/cms/status/event/{topic}", configurator = CmsWebSocketConfigurator.class)
 public class EventEndpoint implements CmsEventSubscriber {
+       private final static CmsLog log = CmsLog.getLog(EventEndpoint.class);
        private BundleContext bc = FrameworkUtil.getBundle(TestEndpoint.class).getBundleContext();
 
        private RemoteEndpoint.Basic remote;
@@ -47,4 +51,13 @@ public class EventEndpoint implements CmsEventSubscriber {
                        throw new IllegalStateException(e);
                }
        }
+
+       @OnError
+       public void onError(Throwable e) {
+               if (e instanceof ClosedChannelException) {
+                       // ignore, as it probably means ping was closed on the other side
+                       return;
+               }
+               log.error("Cannot process ping", e);
+       }
 }
index b81cc591d0ac3f924b98d9c7e4c0e3463ff477dd..dcbce67b17f96bf754061e15e13592e05b1bf7a7 100644 (file)
@@ -1,16 +1,22 @@
 package org.argeo.cms.websocket.server;
 
+import java.nio.channels.ClosedChannelException;
+
 import javax.websocket.OnError;
 import javax.websocket.server.ServerEndpoint;
 
 import org.argeo.api.cms.CmsLog;
 
-@ServerEndpoint(value = "/ping", configurator = PublicWebSocketConfigurator.class)
+@ServerEndpoint(value = "/cms/status/ping", configurator = PublicWebSocketConfigurator.class)
 public class PingEndpoint {
        private final static CmsLog log = CmsLog.getLog(PingEndpoint.class);
 
        @OnError
        public void onError(Throwable e) {
+               if (e instanceof ClosedChannelException) {
+                       // ignore, as it probably means ping was closed on the other side
+                       return;
+               }
                log.error("Cannot process ping", e);
        }
 }
index 0575726d3615681d5f090e9138078a9abc2862b7..f0c7fca3ac2b6c213ec2dbbb6dd79c214ee90972 100644 (file)
@@ -16,9 +16,9 @@ import javax.websocket.Session;
 import javax.websocket.server.PathParam;
 import javax.websocket.server.ServerEndpoint;
 
+import org.argeo.api.acr.ldap.NamingUtils;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.cms.integration.CmsExceptionsChain;
-import org.argeo.util.naming.NamingUtils;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceRegistration;
@@ -31,7 +31,7 @@ import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 /** Provides WebSocket access. */
-@ServerEndpoint(value = "/test/{topic}", configurator = CmsWebSocketConfigurator.class)
+@ServerEndpoint(value = "/cms/status/test/{topic}", configurator = CmsWebSocketConfigurator.class)
 public class TestEndpoint implements EventHandler {
        private final static CmsLog log = CmsLog.getLog(TestEndpoint.class);
 
index 3a978c8ae0f1cb5ec4f3a343ccea2e5f2221a40e..b003c63729c58be246aaa9c5b455e11c9c30d1da 100644 (file)
@@ -1,6 +1,8 @@
 package org.argeo.cms.websocket.server;
 
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 
 import javax.websocket.HandshakeResponse;
 
@@ -14,9 +16,14 @@ public class WebSocketHandshakeResponse implements RemoteAuthResponse {
        }
 
        @Override
-       public void setHeader(String key, String value) {
-               handshakeResponse.getHeaders().put(key, Collections.singletonList(value));
+       public void setHeader(String headerName, String value) {
+               handshakeResponse.getHeaders().put(headerName, Collections.singletonList(value));
+       }
 
+       @Override
+       public void addHeader(String headerName, String value) {
+               List<String> values = handshakeResponse.getHeaders().getOrDefault(headerName, new ArrayList<>());
+               values.add(value);
        }
 
 }
diff --git a/org.argeo.cms.lib.equinox/.classpath b/org.argeo.cms.lib.equinox/.classpath
deleted file mode 100644 (file)
index 81fe078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/org.argeo.cms.lib.equinox/.gitignore b/org.argeo.cms.lib.equinox/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.cms.lib.equinox/.project b/org.argeo.cms.lib.equinox/.project
deleted file mode 100644 (file)
index c551d5d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.cms.lib.equinox</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ds.core.builder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.cms.lib.equinox/META-INF/.gitignore b/org.argeo.cms.lib.equinox/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml b/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml
deleted file mode 100644 (file)
index 6a13362..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" activate="start" deactivate="stop" name="Jetty Service Factory">
-   <implementation class="org.argeo.cms.equinox.http.jetty.EquinoxJettyServer"/>
-   <property name="service.pid" type="String" value="org.argeo.equinox.jetty.config"/>
-   <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
-   <service>
-      <provide interface="com.sun.net.httpserver.HttpServer"/>
-   </service>
-</scr:component>
diff --git a/org.argeo.cms.lib.equinox/bnd.bnd b/org.argeo.cms.lib.equinox/bnd.bnd
deleted file mode 100644 (file)
index 2c83158..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Service-Component: \
-OSGI-INF/jettyServiceFactory.xml,\
diff --git a/org.argeo.cms.lib.equinox/build.properties b/org.argeo.cms.lib.equinox/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java b/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java
deleted file mode 100644 (file)
index 1b1b429..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-package org.argeo.cms.equinox.http.jetty;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import javax.servlet.Servlet;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionIdListener;
-import javax.servlet.http.HttpSessionListener;
-
-import org.argeo.cms.jetty.CmsJettyServer;
-import org.eclipse.equinox.http.servlet.HttpServiceServlet;
-import org.eclipse.jetty.server.session.SessionHandler;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.osgi.framework.Constants;
-
-public class EquinoxJettyServer extends CmsJettyServer {
-       private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader";
-
-       @Override
-       protected void addServlets(ServletContextHandler rootContextHandler) throws ServletException {
-               ServletHolder holder = new ServletHolder(new InternalHttpServiceServlet());
-               holder.setInitOrder(0);
-               holder.setInitParameter(Constants.SERVICE_VENDOR, "Eclipse.org"); //$NON-NLS-1$
-               holder.setInitParameter(Constants.SERVICE_DESCRIPTION, "Equinox Jetty-based Http Service"); //$NON-NLS-1$
-
-               // holder.setInitParameter(JettyConstants.CONTEXT_PATH,
-               // httpContext.getContextPath());
-               rootContextHandler.addServlet(holder, "/*");
-
-               // post-start
-               SessionHandler sessionManager = rootContextHandler.getSessionHandler();
-               sessionManager.addEventListener((HttpSessionIdListener) holder.getServlet());
-       }
-
-       public static class InternalHttpServiceServlet implements HttpSessionListener, HttpSessionIdListener, Servlet {
-               private final Servlet httpServiceServlet = new HttpServiceServlet();
-               private ClassLoader contextLoader;
-               private final Method sessionDestroyed;
-               private final Method sessionIdChanged;
-
-               public InternalHttpServiceServlet() {
-                       Class<?> clazz = httpServiceServlet.getClass();
-
-                       try {
-                               sessionDestroyed = clazz.getMethod("sessionDestroyed", new Class<?>[] { String.class }); //$NON-NLS-1$
-                       } catch (Exception e) {
-                               throw new IllegalStateException(e);
-                       }
-                       try {
-                               sessionIdChanged = clazz.getMethod("sessionIdChanged", new Class<?>[] { String.class }); //$NON-NLS-1$
-                       } catch (Exception e) {
-                               throw new IllegalStateException(e);
-                       }
-               }
-
-               @Override
-               public void init(ServletConfig config) throws ServletException {
-                       ServletContext context = config.getServletContext();
-                       contextLoader = (ClassLoader) context.getAttribute(INTERNAL_CONTEXT_CLASSLOADER);
-
-                       Thread thread = Thread.currentThread();
-                       ClassLoader current = thread.getContextClassLoader();
-                       thread.setContextClassLoader(contextLoader);
-                       try {
-                               httpServiceServlet.init(config);
-                       } finally {
-                               thread.setContextClassLoader(current);
-                       }
-               }
-
-               @Override
-               public void destroy() {
-                       Thread thread = Thread.currentThread();
-                       ClassLoader current = thread.getContextClassLoader();
-                       thread.setContextClassLoader(contextLoader);
-                       try {
-                               httpServiceServlet.destroy();
-                       } finally {
-                               thread.setContextClassLoader(current);
-                       }
-                       contextLoader = null;
-               }
-
-               @Override
-               public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
-                       Thread thread = Thread.currentThread();
-                       ClassLoader current = thread.getContextClassLoader();
-                       thread.setContextClassLoader(contextLoader);
-                       try {
-                               httpServiceServlet.service(req, res);
-                       } finally {
-                               thread.setContextClassLoader(current);
-                       }
-               }
-
-               @Override
-               public ServletConfig getServletConfig() {
-                       return httpServiceServlet.getServletConfig();
-               }
-
-               @Override
-               public String getServletInfo() {
-                       return httpServiceServlet.getServletInfo();
-               }
-
-               @Override
-               public void sessionCreated(HttpSessionEvent event) {
-                       // Nothing to do.
-               }
-
-               @Override
-               public void sessionDestroyed(HttpSessionEvent event) {
-                       Thread thread = Thread.currentThread();
-                       ClassLoader current = thread.getContextClassLoader();
-                       thread.setContextClassLoader(contextLoader);
-                       try {
-                               sessionDestroyed.invoke(httpServiceServlet, event.getSession().getId());
-                       } catch (IllegalAccessException | IllegalArgumentException e) {
-                               // not likely
-                       } catch (InvocationTargetException e) {
-                               throw new RuntimeException(e.getCause());
-                       } finally {
-                               thread.setContextClassLoader(current);
-                       }
-               }
-
-               @Override
-               public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) {
-                       Thread thread = Thread.currentThread();
-                       ClassLoader current = thread.getContextClassLoader();
-                       thread.setContextClassLoader(contextLoader);
-                       try {
-                               sessionIdChanged.invoke(httpServiceServlet, oldSessionId);
-                       } catch (IllegalAccessException | IllegalArgumentException e) {
-                               // not likely
-                       } catch (InvocationTargetException e) {
-                               throw new RuntimeException(e.getCause());
-                       } finally {
-                               thread.setContextClassLoader(current);
-                       }
-               }
-       }
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java b/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java
deleted file mode 100644 (file)
index 50be8b7..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-package org.argeo.cms.servlet.internal.jetty;
-
-import java.io.File;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.concurrent.ForkJoinPool;
-
-import javax.websocket.DeploymentException;
-import javax.websocket.server.ServerContainer;
-import javax.websocket.server.ServerEndpointConfig;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.CmsState;
-import org.argeo.cms.CmsDeployProperty;
-import org.argeo.cms.websocket.server.CmsWebSocketConfigurator;
-import org.argeo.cms.websocket.server.TestEndpoint;
-import org.argeo.util.LangUtils;
-import org.eclipse.equinox.http.jetty.JettyConfigurator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class JettyConfig {
-       private final static CmsLog log = CmsLog.getLog(JettyConfig.class);
-
-       final static String CMS_JETTY_CUSTOMIZER_CLASS = "org.argeo.equinox.jetty.CmsJettyCustomizer";
-
-       private CmsState cmsState;
-
-       private final BundleContext bc = FrameworkUtil.getBundle(JettyConfig.class).getBundleContext();
-
-       // private static final String JETTY_PROPERTY_PREFIX =
-       // "org.eclipse.equinox.http.jetty.";
-
-       public void start() {
-               // We need to start asynchronously so that Jetty bundle get started by lazy init
-               // due to the non-configurable behaviour of its activator
-               ForkJoinPool.commonPool().execute(() -> {
-                       Dictionary<String, Object> properties = getHttpServerConfig();
-                       startServer(properties);
-               });
-
-               ServiceTracker<ServerContainer, ServerContainer> serverSt = new ServiceTracker<ServerContainer, ServerContainer>(
-                               bc, ServerContainer.class, null) {
-
-                       @Override
-                       public ServerContainer addingService(ServiceReference<ServerContainer> reference) {
-                               ServerContainer serverContainer = super.addingService(reference);
-
-                               BundleContext bc = reference.getBundle().getBundleContext();
-                               ServiceReference<ServerEndpointConfig.Configurator> srConfigurator = bc
-                                               .getServiceReference(ServerEndpointConfig.Configurator.class);
-                               ServerEndpointConfig.Configurator endpointConfigurator = bc.getService(srConfigurator);
-                               ServerEndpointConfig config = ServerEndpointConfig.Builder
-                                               .create(TestEndpoint.class, "/ws/test/events/").configurator(endpointConfigurator).build();
-                               try {
-                                       serverContainer.addEndpoint(config);
-                               } catch (DeploymentException e) {
-                                       throw new IllegalStateException("Cannot initalise the WebSocket server runtime.", e);
-                               }
-                               return serverContainer;
-                       }
-
-               };
-               serverSt.open();
-
-               // check initialisation
-//             ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
-//
-//                     @Override
-//                     public HttpService addingService(ServiceReference<HttpService> sr) {
-//                             Object httpPort = sr.getProperty("http.port");
-//                             Object httpsPort = sr.getProperty("https.port");
-//                             log.info(httpPortsMsg(httpPort, httpsPort));
-//                             close();
-//                             return super.addingService(sr);
-//                     }
-//             };
-//             httpSt.open();
-       }
-
-       public void stop() {
-               try {
-                       JettyConfigurator.stopServer(CmsConstants.DEFAULT);
-               } catch (Exception e) {
-                       log.error("Cannot stop default Jetty server.", e);
-               }
-
-       }
-
-       public void startServer(Dictionary<String, Object> properties) {
-               // Explicitly configures Jetty so that the default server is not started by the
-               // activator of the Equinox Jetty bundle.
-               Map<String, String> config = LangUtils.dictToStringMap(properties);
-               if (!config.isEmpty()) {
-                       config.put("customizer.class", CMS_JETTY_CUSTOMIZER_CLASS);
-
-                       // TODO centralise with Jetty extender
-                       Object webSocketEnabled = config.get(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty());
-                       if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
-                               bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null);
-                               // config.put(WEBSOCKET_ENABLED, "true");
-                       }
-               }
-
-               properties.put(Constants.SERVICE_PID, "default");
-               File jettyWorkDir = new File(bc.getDataFile(""), "jettywork"); //$NON-NLS-1$
-               jettyWorkDir.mkdir();
-
-//             HttpServerManager serverManager = new HttpServerManager(jettyWorkDir);
-//             try {
-//                     serverManager.updated("default", properties);
-//             } catch (ConfigurationException e) {
-//                     // TODO Auto-generated catch block
-//                     e.printStackTrace();
-//             }
-               Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
-               Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
-               log.info(httpPortsMsg(httpPort, httpsPort));
-
-//             long begin = System.currentTimeMillis();
-//             int tryCount = 60;
-//             try {
-//                     while (tryCount > 0) {
-//                             try {
-//                                     // FIXME deal with multiple ids
-//                                     JettyConfigurator.startServer(CmsConstants.DEFAULT, new Hashtable<>(config));
-//
-//                                     Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
-//                                     Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
-//                                     log.info(httpPortsMsg(httpPort, httpsPort));
-//
-//                                     // Explicitly starts Jetty OSGi HTTP bundle, so that it gets triggered if OSGi
-//                                     // configuration is not cleaned
-//                                     FrameworkUtil.getBundle(JettyConfigurator.class).start();
-//                                     return;
-//                             } catch (IllegalStateException e) {
-//                                     // e.printStackTrace();
-//                                     // Jetty may not be ready
-//                                     try {
-//                                             Thread.sleep(1000);
-//                                     } catch (Exception e1) {
-//                                             // silent
-//                                     }
-//                                     tryCount--;
-//                             }
-//                     }
-//                     long duration = System.currentTimeMillis() - begin;
-//                     log.error("Gave up with starting Jetty server after " + (duration / 1000) + " s");
-//             } catch (Exception e) {
-//                     log.error("Cannot start default Jetty server with config " + properties, e);
-//             }
-
-       }
-
-       private String httpPortsMsg(Object httpPort, Object httpsPort) {
-               return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
-       }
-
-       /** Override the provided config with the framework properties */
-       public Dictionary<String, Object> getHttpServerConfig() {
-               String httpPort = getFrameworkProp(CmsDeployProperty.HTTP_PORT);
-               String httpsPort = getFrameworkProp(CmsDeployProperty.HTTPS_PORT);
-               /// TODO make it more generic
-               String httpHost = getFrameworkProp(CmsDeployProperty.HOST);
-//             String httpsHost = getFrameworkProp(
-//                             JettyConfig.JETTY_PROPERTY_PREFIX + CmsHttpConstants.HTTPS_HOST);
-               String webSocketEnabled = getFrameworkProp(CmsDeployProperty.WEBSOCKET_ENABLED);
-
-               final Hashtable<String, Object> props = new Hashtable<String, Object>();
-               // try {
-               if (httpPort != null || httpsPort != null) {
-                       boolean httpEnabled = httpPort != null;
-                       props.put(JettyHttpConstants.HTTP_ENABLED, httpEnabled);
-                       boolean httpsEnabled = httpsPort != null;
-                       props.put(JettyHttpConstants.HTTPS_ENABLED, httpsEnabled);
-
-                       if (httpEnabled) {
-                               props.put(JettyHttpConstants.HTTP_PORT, httpPort);
-                               if (httpHost != null)
-                                       props.put(JettyHttpConstants.HTTP_HOST, httpHost);
-                       }
-
-                       if (httpsEnabled) {
-                               props.put(JettyHttpConstants.HTTPS_PORT, httpsPort);
-                               if (httpHost != null)
-                                       props.put(JettyHttpConstants.HTTPS_HOST, httpHost);
-
-                               // keystore
-                               props.put(JettyHttpConstants.SSL_KEYSTORETYPE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORETYPE));
-                               props.put(JettyHttpConstants.SSL_KEYSTORE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORE));
-                               props.put(JettyHttpConstants.SSL_PASSWORD, getFrameworkProp(CmsDeployProperty.SSL_PASSWORD));
-
-                               // truststore
-                               props.put(JettyHttpConstants.SSL_TRUSTSTORETYPE,
-                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORETYPE));
-                               props.put(JettyHttpConstants.SSL_TRUSTSTORE, getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORE));
-                               props.put(JettyHttpConstants.SSL_TRUSTSTOREPASSWORD,
-                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
-
-                               // client certificate authentication
-                               String wantClientAuth = getFrameworkProp(CmsDeployProperty.SSL_WANTCLIENTAUTH);
-                               if (wantClientAuth != null)
-                                       props.put(JettyHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
-                               String needClientAuth = getFrameworkProp(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
-                               if (needClientAuth != null)
-                                       props.put(JettyHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
-                       }
-
-                       // web socket
-                       if (webSocketEnabled != null && webSocketEnabled.equals("true"))
-                               props.put(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty(), true);
-
-                       props.put(CmsConstants.CN, CmsConstants.DEFAULT);
-               }
-               return props;
-       }
-
-       private String getFrameworkProp(CmsDeployProperty deployProperty) {
-               return cmsState.getDeployProperty(deployProperty.getProperty());
-       }
-
-       public void setCmsState(CmsState cmsState) {
-               this.cmsState = cmsState;
-       }
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java b/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java
deleted file mode 100644 (file)
index 8ceb358..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.argeo.cms.servlet.internal.jetty;
-
-/** Compatible with Jetty. */
-interface JettyHttpConstants {
-       static final String HTTP_ENABLED = "http.enabled";
-       static final String HTTP_PORT = "http.port";
-       static final String HTTP_HOST = "http.host";
-       static final String HTTPS_ENABLED = "https.enabled";
-       static final String HTTPS_HOST = "https.host";
-       static final String HTTPS_PORT = "https.port";
-       static final String SSL_KEYSTORE = "ssl.keystore";
-       static final String SSL_PASSWORD = "ssl.password";
-       static final String SSL_KEYPASSWORD = "ssl.keypassword";
-       static final String SSL_NEEDCLIENTAUTH = "ssl.needclientauth";
-       static final String SSL_WANTCLIENTAUTH = "ssl.wantclientauth";
-       static final String SSL_PROTOCOL = "ssl.protocol";
-       static final String SSL_ALGORITHM = "ssl.algorithm";
-       static final String SSL_KEYSTORETYPE = "ssl.keystoretype";
-
-       // Argeo
-       static final String SSL_TRUSTSTORE = "ssl.truststore";
-       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
-       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java b/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java
deleted file mode 100644 (file)
index 7be23fc..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.argeo.equinox.jetty;
-
-import java.util.Dictionary;
-
-import javax.servlet.ServletContext;
-import javax.websocket.DeploymentException;
-import javax.websocket.server.ServerContainer;
-
-import org.eclipse.equinox.http.jetty.JettyCustomizer;
-import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
-import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-/** Customises the Jetty HTTP server. */
-public class CmsJettyCustomizer extends JettyCustomizer {
-       static final String SSL_TRUSTSTORE = "ssl.truststore";
-       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
-       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
-
-       private BundleContext bc = FrameworkUtil.getBundle(CmsJettyCustomizer.class).getBundleContext();
-
-       public final static String WEBSOCKET_ENABLED = "argeo.websocket.enabled";
-
-       @Override
-       public Object customizeContext(Object context, Dictionary<String, ?> settings) {
-               // WebSocket
-               Object webSocketEnabled = settings.get(WEBSOCKET_ENABLED);
-               if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
-                       ServletContextHandler servletContextHandler = (ServletContextHandler) context;
-                       JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
-
-                               @Override
-                               public void accept(ServletContext servletContext, ServerContainer serverContainer)
-                                               throws DeploymentException {
-                                       bc.registerService(javax.websocket.server.ServerContainer.class, serverContainer, null);
-                               }
-                       });
-               }
-               return super.customizeContext(context, settings);
-
-       }
-
-       @Override
-       public Object customizeHttpsConnector(Object connector, Dictionary<String, ?> settings) {
-               ServerConnector httpsConnector = (ServerConnector) connector;
-               if (httpsConnector != null)
-                       for (ConnectionFactory connectionFactory : httpsConnector.getConnectionFactories()) {
-                               if (connectionFactory instanceof SslConnectionFactory) {
-                                       SslContextFactory.Server sslContextFactory = ((SslConnectionFactory) connectionFactory)
-                                                       .getSslContextFactory();
-                                       sslContextFactory.setTrustStorePath((String) settings.get(SSL_TRUSTSTORE));
-                                       sslContextFactory.setTrustStoreType((String) settings.get(SSL_TRUSTSTORETYPE));
-                                       sslContextFactory.setTrustStorePassword((String) settings.get(SSL_TRUSTSTOREPASSWORD));
-                               }
-                       }
-               return super.customizeHttpsConnector(connector, settings);
-       }
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java b/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java
deleted file mode 100644 (file)
index 41c8ce9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Equinox Jetty extensions. */
-package org.argeo.equinox.jetty;
\ No newline at end of file
index 3d4a57b9e7ff113d38095e2da4541516349e1a66..b0b348d9ccfec48a514b93042cd20b2fc2f87757 100644 (file)
@@ -3,30 +3,26 @@ package org.argeo.cms.jetty;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.concurrent.CompletableFuture;
 
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
 
 import org.eclipse.jetty.server.session.SessionHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
 
+/** A {@link JettyHttpServer} which is compatible with Equinox servlets. */
 public class CmsJettyServer extends JettyHttpServer {
        private static final String CONTEXT_TEMPDIR = "javax.servlet.context.tempdir";
        // Equinox compatibility
        private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader";
-//     private static final CmsLog log = CmsLog.getLog(CmsJettyServer.class);
-
-//     private Server server;
-//     private Path tempDir;
-//
-//     private ServerConnector httpConnector;
-//     private ServerConnector httpsConnector;
        private Path tempDir;
 
-       // WebSocket
-//     private ServerContainer wsServerContainer;
-//     private ServerEndpointConfig.Configurator wsEndpointConfigurator;
-
-//     private Authenticator defaultAuthenticator;
+       private CompletableFuture<ServerContainer> serverContainer = new CompletableFuture<>();
 
        protected void addServlets(ServletContextHandler servletContextHandler) throws ServletException {
        }
@@ -41,6 +37,7 @@ public class CmsJettyServer extends JettyHttpServer {
                super.start();
        }
 
+       @Override
        protected ServletContextHandler createRootContextHandler() {
                ServletContextHandler servletContextHandler = new ServletContextHandler();
                servletContextHandler.setAttribute(INTERNAL_CONTEXT_CLASSLOADER,
@@ -53,51 +50,30 @@ public class CmsJettyServer extends JettyHttpServer {
                handler.setMaxInactiveInterval(-1);
                servletContextHandler.setSessionHandler(handler);
 
+               JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
+
+                       @Override
+                       public void accept(ServletContext servletContext, ServerContainer serverContainer)
+                                       throws DeploymentException {
+                               CmsJettyServer.this.serverContainer.complete(serverContainer);
+                       }
+               });
+
                return servletContextHandler;
        }
 
+       @Override
+       protected ServerContainer getRootServerContainer() {
+               return serverContainer.join();
+       }
+
        @Override
        protected void configureRootContextHandler(ServletContextHandler servletContextHandler) throws ServletException {
                addServlets(servletContextHandler);
-//             enableWebSocket(servletContextHandler);
-
        }
 
-//     @Override
-//     public synchronized HttpContext createContext(String path) {
-//             HttpContext httpContext = super.createContext(path);
-//             httpContext.setAuthenticator(defaultAuthenticator);
-//             return httpContext;
-//     }
-
-//     protected void enableWebSocket(ServletContextHandler servletContextHandler) {
-//             String webSocketEnabled = getDeployProperty(CmsDeployProperty.WEBSOCKET_ENABLED);
-//             // web socket
-//             if (webSocketEnabled != null && webSocketEnabled.equals(Boolean.toString(true))) {
-////                   JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
-////
-////                           @Override
-////                           public void accept(ServletContext servletContext, ServerContainer serverContainer)
-////                                           throws DeploymentException {
-//////                                 wsServerContainer = serverContainer;
-////
-////                                   CmsWebSocketConfigurator wsEndpointConfigurator = new CmsWebSocketConfigurator();
-////
-////                                   ServerEndpointConfig config = ServerEndpointConfig.Builder
-////                                                   .create(TestEndpoint.class, "/ws/test/events/{topic}").configurator(wsEndpointConfigurator)
-////                                                   .build();
-////                                   try {
-////                                           serverContainer.addEndpoint(config);
-////                                   } catch (DeploymentException e) {
-////                                           throw new IllegalStateException("Cannot initalise the WebSocket server runtime.", e);
-////                                   }
-////                           }
-////                   });
-//             }
-//     }
-
-//     public void setDefaultAuthenticator(Authenticator defaultAuthenticator) {
-//             this.defaultAuthenticator = defaultAuthenticator;
-//     }
+       /*
+        * WEB SOCKET
+        */
 
 }
diff --git a/org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ContextHandlerAttributes.java b/org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ContextHandlerAttributes.java
new file mode 100644 (file)
index 0000000..1e64fe0
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.cms.jetty;
+
+import java.util.AbstractMap;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+/**
+ * A {@link Map} implementation wrapping the attributes of a Jetty
+ * {@link ContextHandler}.
+ */
+class ContextHandlerAttributes extends AbstractMap<String, Object> {
+       private ContextHandler contextHandler;
+
+       public ContextHandlerAttributes(ContextHandler contextHandler) {
+               super();
+               this.contextHandler = contextHandler;
+       }
+
+       @Override
+       public Set<Entry<String, Object>> entrySet() {
+               Set<Entry<String, Object>> entries = new HashSet<>();
+               for (Enumeration<String> keys = contextHandler.getAttributeNames(); keys.hasMoreElements();) {
+                       entries.add(new ContextAttributeEntry(keys.nextElement()));
+               }
+               return entries;
+       }
+
+       @Override
+       public Object put(String key, Object value) {
+               Object previousValue = get(key);
+               contextHandler.setAttribute(key, value);
+               return previousValue;
+       }
+
+       private class ContextAttributeEntry implements Map.Entry<String, Object> {
+               private final String key;
+
+               public ContextAttributeEntry(String key) {
+                       this.key = key;
+               }
+
+               @Override
+               public String getKey() {
+                       return key;
+               }
+
+               @Override
+               public Object getValue() {
+                       return contextHandler.getAttribute(key);
+               }
+
+               @Override
+               public Object setValue(Object value) {
+                       Object previousValue = getValue();
+                       contextHandler.setAttribute(key, value);
+                       return previousValue;
+               }
+
+       }
+}
diff --git a/org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ContextHandlerHttpContext.java b/org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ContextHandlerHttpContext.java
new file mode 100644 (file)
index 0000000..d6037ba
--- /dev/null
@@ -0,0 +1,84 @@
+package org.argeo.cms.jetty;
+
+import java.util.AbstractMap;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+
+import org.argeo.cms.servlet.httpserver.HttpContextServlet;
+import org.argeo.cms.websocket.server.WebsocketEndpoints;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
+
+import com.sun.net.httpserver.HttpHandler;
+
+/**
+ * An @{HttpContext} implementation based on a Jetty
+ * {@link ServletContextHandler}.
+ */
+class ContextHandlerHttpContext extends JettyHttpContext {
+       private final ServletContextHandler servletContextHandler;
+       private final ContextHandlerAttributes attributes;
+
+       public ContextHandlerHttpContext(JettyHttpServer httpServer, String path) {
+               super(httpServer, path);
+
+               // Jetty context handler
+               this.servletContextHandler = new ServletContextHandler();
+               servletContextHandler.setContextPath(path);
+               HttpContextServlet servlet = new HttpContextServlet(this);
+               servletContextHandler.addServlet(new ServletHolder(servlet), "/*");
+               SessionHandler sessionHandler = new SessionHandler();
+               // FIXME find a better default
+               sessionHandler.setMaxInactiveInterval(-1);
+               servletContextHandler.setSessionHandler(sessionHandler);
+
+               attributes = new ContextHandlerAttributes(servletContextHandler);
+       }
+
+       @Override
+       public void setHandler(HttpHandler handler) {
+               super.setHandler(handler);
+
+               // web socket
+               if (handler instanceof WebsocketEndpoints) {
+                       JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
+
+                               @Override
+                               public void accept(ServletContext servletContext, ServerContainer serverContainer)
+                                               throws DeploymentException {
+                                       for (Class<?> clss : ((WebsocketEndpoints) handler).getEndPoints()) {
+                                               serverContainer.addEndpoint(clss);
+                                       }
+                               }
+                       });
+               }
+
+               if (getJettyHttpServer().isStarted())
+                       try {
+                               servletContextHandler.start();
+                       } catch (Exception e) {
+                               throw new IllegalStateException("Cannot start context handler", e);
+                       }
+       }
+
+       @Override
+       public Map<String, Object> getAttributes() {
+               return attributes;
+       }
+
+       @Override
+       protected ServletContextHandler getServletContextHandler() {
+               return servletContextHandler;
+       }
+
+}
index 5876d52e8ae72027c5a9deaa68e815affbf89ae9..551e54e05044410f334694cf9c5641b512ee2a48 100644 (file)
@@ -1,23 +1,15 @@
 package org.argeo.cms.jetty;
 
-import java.util.AbstractMap;
 import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 
 import javax.servlet.ServletContext;
 import javax.websocket.DeploymentException;
 import javax.websocket.server.ServerContainer;
 
-import org.argeo.cms.servlet.httpserver.HttpContextServlet;
 import org.argeo.cms.websocket.server.WebsocketEndpoints;
-import org.eclipse.jetty.server.session.SessionHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
 import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
 
@@ -27,12 +19,13 @@ import com.sun.net.httpserver.HttpContext;
 import com.sun.net.httpserver.HttpHandler;
 import com.sun.net.httpserver.HttpServer;
 
-/** Trivial implementation of @{HttpContext}. */
-class JettyHttpContext extends HttpContext {
+/**
+ * An @{HttpContext} implementation based on Jetty. It supports web sockets if
+ * the handler implements {@link WebsocketEndpoints}.
+ */
+abstract class JettyHttpContext extends HttpContext {
        private final JettyHttpServer httpServer;
        private final String path;
-       private final ServletContextHandler contextHandler;
-       private final ContextAttributes attributes;
        private final List<Filter> filters = new ArrayList<>();
 
        private HttpHandler handler;
@@ -40,22 +33,13 @@ class JettyHttpContext extends HttpContext {
 
        public JettyHttpContext(JettyHttpServer httpServer, String path) {
                this.httpServer = httpServer;
+               if (!path.endsWith("/"))
+                       throw new IllegalArgumentException("Path " + path + " should end with a /");
                this.path = path;
-
-               // Jetty context handler
-               ServletContextHandler servletContextHandler = new ServletContextHandler();
-               servletContextHandler.setContextPath(path);
-               HttpContextServlet servlet = new HttpContextServlet(this);
-               servletContextHandler.addServlet(new ServletHolder(servlet), "/*");
-               SessionHandler sessionHandler = new SessionHandler();
-               // FIXME find a better default
-               sessionHandler.setMaxInactiveInterval(-1);
-               servletContextHandler.setSessionHandler(sessionHandler);
-               contextHandler = servletContextHandler;
-
-               attributes = new ContextAttributes();
        }
 
+       protected abstract ServletContextHandler getServletContextHandler();
+
        @Override
        public HttpHandler getHandler() {
                return handler;
@@ -67,32 +51,6 @@ class JettyHttpContext extends HttpContext {
                        throw new IllegalArgumentException("Handler is already set");
                Objects.requireNonNull(handler);
                this.handler = handler;
-
-               // web socket
-               if (handler instanceof WebsocketEndpoints) {
-                       JavaxWebSocketServletContainerInitializer.configure(contextHandler, new Configurator() {
-
-                               @Override
-                               public void accept(ServletContext servletContext, ServerContainer serverContainer)
-                                               throws DeploymentException {
-//                                     CmsWebSocketConfigurator wsEndpointConfigurator = new CmsWebSocketConfigurator();
-
-                                       for (Class<?> clss : ((WebsocketEndpoints) handler).getEndPoints()) {
-//                                             Class<?> clss = websocketEndpoints.get(path);
-//                                             ServerEndpointConfig config = ServerEndpointConfig.Builder.create(clss, path)
-//                                                             .configurator(wsEndpointConfigurator).build();
-                                               serverContainer.addEndpoint(clss);
-                                       }
-                               }
-                       });
-               }
-
-               if (httpServer.isStarted())
-                       try {
-                               contextHandler.start();
-                       } catch (Exception e) {
-                               throw new IllegalStateException("Cannot start context handler", e);
-                       }
        }
 
        @Override
@@ -102,12 +60,11 @@ class JettyHttpContext extends HttpContext {
 
        @Override
        public HttpServer getServer() {
-               return httpServer;
+               return getJettyHttpServer();
        }
 
-       @Override
-       public Map<String, Object> getAttributes() {
-               return attributes;
+       protected JettyHttpServer getJettyHttpServer() {
+               return httpServer;
        }
 
        @Override
@@ -127,51 +84,4 @@ class JettyHttpContext extends HttpContext {
                return authenticator;
        }
 
-       ServletContextHandler getContextHandler() {
-               return contextHandler;
-       }
-
-       private class ContextAttributes extends AbstractMap<String, Object> {
-               @Override
-               public Set<Entry<String, Object>> entrySet() {
-                       Set<Entry<String, Object>> entries = new HashSet<>();
-                       for (Enumeration<String> keys = contextHandler.getAttributeNames(); keys.hasMoreElements();) {
-                               entries.add(new ContextAttributeEntry(keys.nextElement()));
-                       }
-                       return entries;
-               }
-
-               @Override
-               public Object put(String key, Object value) {
-                       Object previousValue = get(key);
-                       contextHandler.setAttribute(key, value);
-                       return previousValue;
-               }
-
-               private class ContextAttributeEntry implements Map.Entry<String, Object> {
-                       private final String key;
-
-                       public ContextAttributeEntry(String key) {
-                               this.key = key;
-                       }
-
-                       @Override
-                       public String getKey() {
-                               return key;
-                       }
-
-                       @Override
-                       public Object getValue() {
-                               return contextHandler.getAttribute(key);
-                       }
-
-                       @Override
-                       public Object setValue(Object value) {
-                               Object previousValue = getValue();
-                               contextHandler.setAttribute(key, value);
-                               return previousValue;
-                       }
-
-               }
-       }
 }
index 80cff8b012bba5e5f55b56dd9a9fcd2e5924eac3..363bbaebe498362973675995c4c63e7c18e20ab6 100644 (file)
@@ -8,11 +8,12 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.ThreadPoolExecutor;
 
 import javax.servlet.ServletException;
+import javax.websocket.server.ServerContainer;
 
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsState;
 import org.argeo.cms.CmsDeployProperty;
-import org.argeo.util.http.HttpServerUtils;
+import org.argeo.cms.http.server.HttpServerUtils;
 import org.eclipse.jetty.http.UriCompliance;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
@@ -32,6 +33,7 @@ import com.sun.net.httpserver.HttpHandler;
 import com.sun.net.httpserver.HttpsConfigurator;
 import com.sun.net.httpserver.HttpsServer;
 
+/** An {@link HttpServer} implementation based on Jetty. */
 public class JettyHttpServer extends HttpsServer {
        private final static CmsLog log = CmsLog.getLog(JettyHttpServer.class);
 
@@ -51,6 +53,7 @@ public class JettyHttpServer extends HttpsServer {
 
        private final Map<String, JettyHttpContext> contexts = new TreeMap<>();
 
+       private ServletContextHandler rootContextHandler;
        protected final ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
 
        private boolean started;
@@ -91,19 +94,13 @@ public class JettyHttpServer extends HttpsServer {
                        // holder
 
                        // context
-                       ServletContextHandler rootContextHandler = createRootContextHandler();
+                       rootContextHandler = createRootContextHandler();
                        // httpContext.addServlet(holder, "/*");
                        if (rootContextHandler != null)
                                configureRootContextHandler(rootContextHandler);
-//                     server.setHandler(rootContextHandler);
 
-//                     ContextHandlerCollection contextHandlers = new ContextHandlerCollection();
                        if (rootContextHandler != null && !contexts.containsKey("/"))
                                contextHandlerCollection.addHandler(rootContextHandler);
-//                     for (String contextPath : contexts.keySet()) {
-//                             JettyHttpContext ctx = contexts.get(contextPath);
-//                             contextHandlers.addHandler(ctx.getContextHandler());
-//                     }
 
                        server.setHandler(contextHandlerCollection);
 
@@ -115,20 +112,93 @@ public class JettyHttpServer extends HttpsServer {
                        // Addresses
                        String httpHost = getDeployProperty(CmsDeployProperty.HOST);
                        String fallBackHostname = cmsState != null ? cmsState.getHostname() : "::1";
-                       if (httpConnector != null)
+                       if (httpConnector != null) {
                                httpAddress = new InetSocketAddress(httpHost != null ? httpHost : fallBackHostname,
                                                httpConnector.getLocalPort());
-                       if (httpsConnector != null)
+                       } else if (httpsConnector != null) {
                                httpsAddress = new InetSocketAddress(httpHost != null ? httpHost : fallBackHostname,
                                                httpsConnector.getLocalPort());
-
+                       }
                        // Clean up
                        Runtime.getRuntime().addShutdownHook(new Thread(() -> stop(), "Jetty shutdown"));
 
                        log.info(httpPortsMsg());
                        started = true;
                } catch (Exception e) {
-                       throw new IllegalStateException("Cannot start Jetty HTTPS server", e);
+                       stop();
+                       throw new IllegalStateException("Cannot start Jetty HTTP server", e);
+               }
+       }
+
+       protected void configureConnectors() {
+               String httpPortStr = getDeployProperty(CmsDeployProperty.HTTP_PORT);
+               String httpsPortStr = getDeployProperty(CmsDeployProperty.HTTPS_PORT);
+               if (httpPortStr != null && httpsPortStr != null)
+                       throw new IllegalArgumentException("Either an HTTP or an HTTPS port should be configured, not both");
+               if (httpPortStr == null && httpsPortStr == null)
+                       throw new IllegalArgumentException("Neither an HTTP or HTTPS port was configured");
+
+               /// TODO make it more generic
+               String httpHost = getDeployProperty(CmsDeployProperty.HOST);
+
+               // try {
+               if (httpPortStr != null || httpsPortStr != null) {
+                       // TODO deal with hostname resolving taking too much time
+//                     String fallBackHostname = InetAddress.getLocalHost().getHostName();
+
+                       boolean httpEnabled = httpPortStr != null;
+                       boolean httpsEnabled = httpsPortStr != null;
+
+                       if (httpEnabled) {
+                               HttpConfiguration httpConfiguration = new HttpConfiguration();
+
+                               if (httpsEnabled) {// not supported anymore to have both http and https, but it may change again
+                                       int httpsPort = Integer.parseInt(httpsPortStr);
+                                       httpConfiguration.setSecureScheme("https");
+                                       httpConfiguration.setSecurePort(httpsPort);
+                               }
+
+                               int httpPort = Integer.parseInt(httpPortStr);
+                               httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
+                               httpConnector.setPort(httpPort);
+                               httpConnector.setHost(httpHost);
+                               httpConnector.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
+
+                       }
+
+                       if (httpsEnabled) {
+                               SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
+                               // sslContextFactory.setKeyStore(KeyS)
+
+                               sslContextFactory.setKeyStoreType(getDeployProperty(CmsDeployProperty.SSL_KEYSTORETYPE));
+                               sslContextFactory.setKeyStorePath(getDeployProperty(CmsDeployProperty.SSL_KEYSTORE));
+                               sslContextFactory.setKeyStorePassword(getDeployProperty(CmsDeployProperty.SSL_PASSWORD));
+                               // sslContextFactory.setKeyManagerPassword(getFrameworkProp(CmsDeployProperty.SSL_KEYPASSWORD));
+                               sslContextFactory.setProtocol("TLS");
+
+                               sslContextFactory.setTrustStoreType(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORETYPE));
+                               sslContextFactory.setTrustStorePath(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORE));
+                               sslContextFactory.setTrustStorePassword(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
+
+                               String wantClientAuth = getDeployProperty(CmsDeployProperty.SSL_WANTCLIENTAUTH);
+                               if (wantClientAuth != null && wantClientAuth.equals(Boolean.toString(true)))
+                                       sslContextFactory.setWantClientAuth(true);
+                               String needClientAuth = getDeployProperty(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
+                               if (needClientAuth != null && needClientAuth.equals(Boolean.toString(true)))
+                                       sslContextFactory.setNeedClientAuth(true);
+
+                               // HTTPS Configuration
+                               HttpConfiguration httpsConfiguration = new HttpConfiguration();
+                               httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
+                               httpsConfiguration.setUriCompliance(UriCompliance.LEGACY);
+
+                               // HTTPS connector
+                               httpsConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"),
+                                               new HttpConnectionFactory(httpsConfiguration));
+                               int httpsPort = Integer.parseInt(httpsPortStr);
+                               httpsConnector.setPort(httpsPort);
+                               httpsConnector.setHost(httpHost);
+                       }
                }
        }
 
@@ -141,12 +211,11 @@ public class JettyHttpServer extends HttpsServer {
 
        public void stop() {
                try {
-                       // serverConnector.close();
                        server.stop();
                        // TODO delete temp dir
                        started = false;
                } catch (Exception e) {
-                       e.printStackTrace();
+                       log.error("Cannot stop Jetty HTTP server", e);
                }
 
        }
@@ -172,12 +241,15 @@ public class JettyHttpServer extends HttpsServer {
 
        @Override
        public synchronized HttpContext createContext(String path) {
+               if (!path.endsWith("/"))
+                       path = path + "/";
                if (contexts.containsKey(path))
                        throw new IllegalArgumentException("Context " + path + " already exists");
-               JettyHttpContext httpContext = new JettyHttpContext(this, path);
+
+               JettyHttpContext httpContext = new ServletHttpContext(this, path);
                contexts.put(path, httpContext);
 
-               contextHandlerCollection.addHandler(httpContext.getContextHandler());
+               contextHandlerCollection.addHandler(httpContext.getServletContextHandler());
                return httpContext;
        }
 
@@ -186,8 +258,10 @@ public class JettyHttpServer extends HttpsServer {
                if (!contexts.containsKey(path))
                        throw new IllegalArgumentException("Context " + path + " does not exist");
                JettyHttpContext httpContext = contexts.remove(path);
-               // TODO stop handler first?
-               contextHandlerCollection.removeHandler(httpContext.getContextHandler());
+               if (httpContext instanceof ContextHandlerHttpContext contextHandlerHttpContext) {
+                       // TODO stop handler first?
+                       contextHandlerCollection.removeHandler(contextHandlerHttpContext.getServletContextHandler());
+               }
        }
 
        @Override
@@ -197,7 +271,10 @@ public class JettyHttpServer extends HttpsServer {
 
        @Override
        public InetSocketAddress getAddress() {
-               return httpAddress;
+               InetSocketAddress res = httpAddress != null ? httpAddress : httpsAddress;
+               if (res == null)
+                       throw new IllegalStateException("Neither an HTTP nor and HTTPS address is available");
+               return res;
        }
 
        @Override
@@ -210,80 +287,6 @@ public class JettyHttpServer extends HttpsServer {
                return httpsConfigurator;
        }
 
-       protected void configureConnectors() {
-               HttpConfiguration httpConfiguration = new HttpConfiguration();
-
-               String httpPortStr = getDeployProperty(CmsDeployProperty.HTTP_PORT);
-               String httpsPortStr = getDeployProperty(CmsDeployProperty.HTTPS_PORT);
-
-               /// TODO make it more generic
-               String httpHost = getDeployProperty(CmsDeployProperty.HOST);
-//             String httpsHost = getFrameworkProp(
-//                             JettyConfig.JETTY_PROPERTY_PREFIX + CmsHttpConstants.HTTPS_HOST);
-
-               // try {
-               if (httpPortStr != null || httpsPortStr != null) {
-                       // TODO deal with hostname resolving taking too much time
-//                     String fallBackHostname = InetAddress.getLocalHost().getHostName();
-
-                       boolean httpEnabled = httpPortStr != null;
-                       // props.put(JettyHttpConstants.HTTP_ENABLED, httpEnabled);
-                       boolean httpsEnabled = httpsPortStr != null;
-                       // props.put(JettyHttpConstants.HTTPS_ENABLED, httpsEnabled);
-                       if (httpsEnabled) {
-                               int httpsPort = Integer.parseInt(httpsPortStr);
-                               httpConfiguration.setSecureScheme("https");
-                               httpConfiguration.setSecurePort(httpsPort);
-                       }
-
-                       if (httpEnabled) {
-                               int httpPort = Integer.parseInt(httpPortStr);
-                               httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
-                               httpConnector.setPort(httpPort);
-                               httpConnector.setHost(httpHost);
-                               httpConnector.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
-
-                       }
-
-                       if (httpsEnabled) {
-
-                               SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
-                               // sslContextFactory.setKeyStore(KeyS)
-
-                               sslContextFactory.setKeyStoreType(getDeployProperty(CmsDeployProperty.SSL_KEYSTORETYPE));
-                               sslContextFactory.setKeyStorePath(getDeployProperty(CmsDeployProperty.SSL_KEYSTORE));
-                               sslContextFactory.setKeyStorePassword(getDeployProperty(CmsDeployProperty.SSL_PASSWORD));
-                               // sslContextFactory.setKeyManagerPassword(getFrameworkProp(CmsDeployProperty.SSL_KEYPASSWORD));
-                               sslContextFactory.setProtocol("TLS");
-
-                               sslContextFactory.setTrustStoreType(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORETYPE));
-                               sslContextFactory.setTrustStorePath(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORE));
-                               sslContextFactory.setTrustStorePassword(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
-
-                               String wantClientAuth = getDeployProperty(CmsDeployProperty.SSL_WANTCLIENTAUTH);
-                               if (wantClientAuth != null && wantClientAuth.equals(Boolean.toString(true)))
-                                       sslContextFactory.setWantClientAuth(true);
-                               String needClientAuth = getDeployProperty(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
-                               if (needClientAuth != null && needClientAuth.equals(Boolean.toString(true)))
-                                       sslContextFactory.setNeedClientAuth(true);
-
-                               // HTTPS Configuration
-                               HttpConfiguration https_config = new HttpConfiguration(httpConfiguration);
-                               https_config.addCustomizer(new SecureRequestCustomizer());
-                               https_config.setUriCompliance(UriCompliance.LEGACY);
-
-                               // HTTPS connector
-                               httpsConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"),
-                                               new HttpConnectionFactory(https_config));
-                               int httpsPort = Integer.parseInt(httpsPortStr);
-                               httpsConnector.setPort(httpsPort);
-                               httpsConnector.setHost(httpHost);
-                       }
-
-               }
-
-       }
-
        protected String getDeployProperty(CmsDeployProperty deployProperty) {
                return cmsState != null ? cmsState.getDeployProperty(deployProperty.getProperty())
                                : System.getProperty(deployProperty.getProperty());
@@ -291,7 +294,7 @@ public class JettyHttpServer extends HttpsServer {
 
        private String httpPortsMsg() {
 
-               return (httpConnector != null ? "HTTP " + getHttpPort() + " " : " ")
+               return (httpConnector != null ? "HTTP " + getHttpPort() + " " : "")
                                + (httpsConnector != null ? "HTTPS " + getHttpsPort() : "");
        }
 
@@ -319,10 +322,18 @@ public class JettyHttpServer extends HttpsServer {
                this.cmsState = cmsState;
        }
 
-       public boolean isStarted() {
+       boolean isStarted() {
                return started;
        }
 
+       ServletContextHandler getRootContextHandler() {
+               return rootContextHandler;
+       }
+
+       ServerContainer getRootServerContainer() {
+               throw new UnsupportedOperationException();
+       }
+
        public static void main(String... args) {
                JettyHttpServer httpServer = new JettyHttpServer();
                System.setProperty("argeo.http.port", "8080");
diff --git a/org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ServletHttpContext.java b/org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/ServletHttpContext.java
new file mode 100644 (file)
index 0000000..3361194
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.cms.jetty;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.servlet.httpserver.HttpContextServlet;
+import org.argeo.cms.websocket.server.WebsocketEndpoints;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+import com.sun.net.httpserver.HttpHandler;
+
+/**
+ * A {@link JettyHttpContext} based on registering a servlet to the root handler
+ * of the {@link JettyHttpServer}, in order to integrate the sessions.
+ */
+public class ServletHttpContext extends JettyHttpContext {
+       private final static CmsLog log = CmsLog.getLog(ServletHttpContext.class);
+
+       private Map<String, Object> attributes = Collections.synchronizedMap(new HashMap<>());
+
+       public ServletHttpContext(JettyHttpServer httpServer, String path) {
+               super(httpServer, path);
+
+               ServletContextHandler rootContextHandler = httpServer.getRootContextHandler();
+               HttpContextServlet servlet = new HttpContextServlet(this);
+               rootContextHandler.addServlet(new ServletHolder(servlet), path + "*");
+       }
+
+       @Override
+       public void setHandler(HttpHandler handler) {
+               super.setHandler(handler);
+
+               // web socket
+               if (handler instanceof WebsocketEndpoints) {
+                       ServerContainer serverContainer = getJettyHttpServer().getRootServerContainer();
+                       for (Class<?> clss : ((WebsocketEndpoints) handler).getEndPoints()) {
+                               try {
+                                       serverContainer.addEndpoint(clss);
+                                       log.debug(() -> "Added web socket " + clss + " to " + getPath());
+                               } catch (DeploymentException e) {
+                                       log.error("Cannot deploy Web Socket " + clss, e);
+                               }
+                       }
+               }
+       }
+
+       @Override
+       public Map<String, Object> getAttributes() {
+               return attributes;
+       }
+
+       @Override
+       protected ServletContextHandler getServletContextHandler() {
+               return getJettyHttpServer().getRootContextHandler();
+       }
+
+}
diff --git a/org.argeo.cms.lib.pgsql/.classpath b/org.argeo.cms.lib.pgsql/.classpath
deleted file mode 100644 (file)
index 81fe078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/org.argeo.cms.lib.pgsql/.project b/org.argeo.cms.lib.pgsql/.project
deleted file mode 100644 (file)
index 3cd5f6f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.cms.lib.pgsql</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.cms.lib.pgsql/bnd.bnd b/org.argeo.cms.lib.pgsql/bnd.bnd
deleted file mode 100644 (file)
index 9c73009..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Import-Package: org.postgresql;version="[42,43)"
diff --git a/org.argeo.cms.lib.pgsql/build.properties b/org.argeo.cms.lib.pgsql/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/org.argeo.cms.lib.pgsql/src/org/argeo/cms/sql/postgres/CheckPg.java b/org.argeo.cms.lib.pgsql/src/org/argeo/cms/sql/postgres/CheckPg.java
deleted file mode 100644 (file)
index bc002a6..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.argeo.cms.sql.postgres;
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-import org.postgresql.Driver;
-
-/** Simple PostgreSQL check. */
-public class CheckPg {
-
-       public List<String> listTables() {
-               String osUser = System.getProperty("user.name");
-
-               String url = "jdbc:postgresql://localhost/" + osUser;
-               Properties props = new Properties();
-               props.setProperty("user", osUser);
-               props.setProperty("password", "changeit");
-               List<String> result = new ArrayList<>();
-
-               Driver driver = new Driver();
-               try (Connection conn = driver.connect(url, props); Statement s = conn.createStatement();) {
-                       s.execute("SELECT * FROM pg_catalog.pg_tables");
-                       ResultSet rs = s.getResultSet();
-                       while (rs.next()) {
-                               result.add(rs.getString("tablename"));
-                       }
-                       return result;
-               } catch (SQLException e) {
-                       throw new IllegalStateException(e);
-               }
-       }
-
-       public static void main(String[] args) {
-               new CheckPg().listTables().forEach(System.out::println);
-       }
-
-}
diff --git a/org.argeo.cms.lib.sshd/META-INF/native-image/jni-config.json b/org.argeo.cms.lib.sshd/META-INF/native-image/jni-config.json
deleted file mode 100644 (file)
index 7d14cdb..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-[
-{
-  "name":"java.lang.Boolean",
-  "methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.ClassLoader",
-  "methods":[
-    {"name":"getPlatformClassLoader","parameterTypes":[] }, 
-    {"name":"loadClass","parameterTypes":["java.lang.String"] }
-  ]
-},
-{
-  "name":"java.lang.String",
-  "methods":[
-    {"name":"<init>","parameterTypes":["byte[]"] }, 
-    {"name":"getBytes","parameterTypes":[] }
-  ]
-},
-{
-  "name":"jdk.internal.loader.ClassLoaders$PlatformClassLoader"
-},
-{
-  "name":"org.apache.tomcat.jni.FileInfo",
-  "fields":[
-    {"name":"atime"}, 
-    {"name":"csize"}, 
-    {"name":"ctime"}, 
-    {"name":"device"}, 
-    {"name":"filehand"}, 
-    {"name":"filetype"}, 
-    {"name":"fname"}, 
-    {"name":"group"}, 
-    {"name":"inode"}, 
-    {"name":"mtime"}, 
-    {"name":"name"}, 
-    {"name":"nlink"}, 
-    {"name":"pool"}, 
-    {"name":"protection"}, 
-    {"name":"size"}, 
-    {"name":"user"}, 
-    {"name":"valid"}
-  ],
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.tomcat.jni.Sockaddr",
-  "fields":[
-    {"name":"family"}, 
-    {"name":"hostname"}, 
-    {"name":"next"}, 
-    {"name":"pool"}, 
-    {"name":"port"}, 
-    {"name":"servname"}
-  ],
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.graalvm.jniutils.JNIExceptionWrapperEntryPoints",
-  "methods":[{"name":"getClassName","parameterTypes":["java.lang.Class"] }]
-},
-{
-  "name":"sun.management.VMManagementImpl",
-  "fields":[
-    {"name":"compTimeMonitoringSupport"}, 
-    {"name":"currentThreadCpuTimeSupport"}, 
-    {"name":"objectMonitorUsageSupport"}, 
-    {"name":"otherThreadCpuTimeSupport"}, 
-    {"name":"remoteDiagnosticCommandsSupport"}, 
-    {"name":"synchronizerUsageSupport"}, 
-    {"name":"threadAllocatedMemorySupport"}, 
-    {"name":"threadContentionMonitoringSupport"}
-  ]
-}
-]
diff --git a/org.argeo.cms.lib.sshd/META-INF/native-image/predefined-classes-config.json b/org.argeo.cms.lib.sshd/META-INF/native-image/predefined-classes-config.json
deleted file mode 100644 (file)
index 0e79b2c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-[
-  {
-    "type":"agent-extracted",
-    "classes":[
-    ]
-  }
-]
-
diff --git a/org.argeo.cms.lib.sshd/META-INF/native-image/proxy-config.json b/org.argeo.cms.lib.sshd/META-INF/native-image/proxy-config.json
deleted file mode 100644 (file)
index f9dde34..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-[
-  {
-    "interfaces":["org.apache.sshd.common.channel.ChannelListener"]}
-  ,
-  {
-    "interfaces":["org.apache.sshd.common.forward.PortForwardingEventListener"]}
-  ,
-  {
-    "interfaces":["org.apache.sshd.common.session.SessionListener"]}
-  
-]
diff --git a/org.argeo.cms.lib.sshd/META-INF/native-image/reflect-config.json b/org.argeo.cms.lib.sshd/META-INF/native-image/reflect-config.json
deleted file mode 100644 (file)
index e68e2b5..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-[
-{
-  "name":"java.security.KeyFactory",
-  "methods":[{"name":"getInstance","parameterTypes":["java.lang.String","java.lang.String"] }]
-},
-{
-  "name":"java.security.KeyPairGenerator",
-  "methods":[{"name":"getInstance","parameterTypes":["java.lang.String","java.lang.String"] }]
-},
-{
-  "name":"java.security.MessageDigest",
-  "methods":[{"name":"getInstance","parameterTypes":["java.lang.String","java.lang.String"] }]
-},
-{
-  "name":"java.security.SecureRandomParameters"
-},
-{
-  "name":"java.security.Signature",
-  "methods":[{"name":"getInstance","parameterTypes":["java.lang.String","java.lang.String"] }]
-},
-{
-  "name":"java.security.cert.PKIXRevocationChecker"
-},
-{
-  "name":"javax.crypto.KeyAgreement",
-  "methods":[{"name":"getInstance","parameterTypes":["java.lang.String","java.lang.String"] }]
-},
-{
-  "name":"org.apache.sshd.common.SshConstants",
-  "allPublicFields":true
-},
-{
-  "name":"org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.sshd.common.session.SessionListener",
-  "methods":[
-    {"name":"sessionClosed","parameterTypes":["org.apache.sshd.common.session.Session"] }, 
-    {"name":"sessionCreated","parameterTypes":["org.apache.sshd.common.session.Session"] }, 
-    {"name":"sessionEstablished","parameterTypes":["org.apache.sshd.common.session.Session"] }, 
-    {"name":"sessionEvent","parameterTypes":["org.apache.sshd.common.session.Session","org.apache.sshd.common.session.SessionListener$Event"] }, 
-    {"name":"sessionNegotiationEnd","parameterTypes":["org.apache.sshd.common.session.Session","java.util.Map","java.util.Map","java.util.Map","java.lang.Throwable"] }, 
-    {"name":"sessionNegotiationOptionsCreated","parameterTypes":["org.apache.sshd.common.session.Session","java.util.Map"] }, 
-    {"name":"sessionNegotiationStart","parameterTypes":["org.apache.sshd.common.session.Session","java.util.Map","java.util.Map"] }, 
-    {"name":"sessionPeerIdentificationLine","parameterTypes":["org.apache.sshd.common.session.Session","java.lang.String","java.util.List"] }, 
-    {"name":"sessionPeerIdentificationReceived","parameterTypes":["org.apache.sshd.common.session.Session","java.lang.String","java.util.List"] }, 
-    {"name":"sessionPeerIdentificationSend","parameterTypes":["org.apache.sshd.common.session.Session","java.lang.String","java.util.List"] }
-  ]
-},
-{
-  "name":"org.apache.sshd.common.util.security.bouncycastle.BouncyCastleSecurityProviderRegistrar",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderRegistrar",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.COMPOSITE$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.DSTU4145$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.ECGOST$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.EXTERNAL$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.EdEC$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.ElGamal$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.GM$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.GOST$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.IES$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.LMS$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.RSA$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.SPHINCSPlus$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.X509$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.dh.KeyPairGeneratorSpi",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$EC",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi$EC",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.ec.SignatureSpi$ecDSA256",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyAgreementSpi$X25519",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyAgreementSpi$X448",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyFactorySpi$X25519",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyFactorySpi$X448",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi$X25519",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi$X448",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi$SHA512",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Blake2b$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Blake2s$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Blake3$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.DSTU7564$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.GOST3411$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Haraka$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Keccak$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.MD2$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.MD4$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.MD5$Digest",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.MD5$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD128$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD160$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD256$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD320$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA1$Digest",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA1$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA224$Digest",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA224$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA256$Digest",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA256$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA3$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA384$Digest",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA384$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA512$Digest",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SHA512$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.SM3$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Skein$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Tiger$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.digest.Whirlpool$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.drbg.DRBG$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.keystore.BC$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.keystore.BCFKS$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.AES$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.ARC4$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.ARIA$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Blowfish$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.CAST5$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.CAST6$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Camellia$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.ChaCha$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.DES$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.DSTU7624$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.GOST28147$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.GOST3412_2015$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Grain128$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Grainv1$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.HC128$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.HC256$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Noekeon$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.OpenSSLPBKDF$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF1$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Poly1305$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.RC5$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.RC6$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Rijndael$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.SCRYPT$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.SEED$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.SM4$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Salsa20$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Serpent$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Shacal2$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.SipHash$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.SipHash128$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Skipjack$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.TEA$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.TLSKDF$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Threefish$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.VMPC$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.VMPCKSA3$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.XSalsa20$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.XTEA$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jcajce.provider.symmetric.Zuc$Mappings",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.bouncycastle.jce.provider.BouncyCastleProvider",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.NativePRNG",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.SHA",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-}
-]
diff --git a/org.argeo.cms.lib.sshd/META-INF/native-image/resource-config.json b/org.argeo.cms.lib.sshd/META-INF/native-image/resource-config.json
deleted file mode 100644 (file)
index 7c33b1b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "resources":{
-  "includes":[
-    {
-      "pattern":"\\Qorg/apache/sshd/sshd-version.properties\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/slf4j/impl/StaticLoggerBinder.class\\E"
-    }
-  ]},
-  "bundles":[]
-}
diff --git a/org.argeo.cms.lib.sshd/META-INF/native-image/serialization-config.json b/org.argeo.cms.lib.sshd/META-INF/native-image/serialization-config.json
deleted file mode 100644 (file)
index bf554e0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "types":[
-  ],
-  "lambdaCapturingTypes":[
-  ]
-}
index be41f9cbd9f9bb83df80c70c62d5383884d23dfe..cde6c935ae2aff8e4b8ab135ea2169dfdd7224da 100644 (file)
@@ -9,7 +9,7 @@ import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.config.keys.DefaultAuthorizedKeysAuthenticator;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.server.shell.ProcessShellFactory;
-import org.argeo.util.OS;
+import org.argeo.cms.util.OS;
 
 /** A simple SSH server with some defaults. Supports SCP. */
 public class BasicSshServer {
index 71b6365761f7ee5a7752747f554d230a1b5b69fc..31e63411ad3333202e5b09ea495ace0301ec496a 100644 (file)
@@ -11,7 +11,6 @@ import java.security.KeyPair;
 import java.util.Map;
 import java.util.Scanner;
 
-import org.apache.commons.io.IOUtils;
 import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.agent.local.LocalAgentFactory;
@@ -25,6 +24,7 @@ import org.apache.sshd.common.config.keys.FilePasswordProvider;
 import org.apache.sshd.sftp.client.fs.SftpFileSystem;
 import org.apache.sshd.sftp.client.fs.SftpFileSystemProvider;
 import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.util.StreamUtils;
 
 public class SshSync {
        private final static CmsLog log = CmsLog.getLog(SshSync.class);
@@ -124,7 +124,7 @@ public class SshSync {
                        log.debug("Relative copied file " + relativeCopiedFile);
                        try (OutputStream out = Files.newOutputStream(copiedFile);
                                        InputStream in = Files.newInputStream(testPath)) {
-                               IOUtils.copy(in, out);
+                               StreamUtils.copy(in, out);
                        }
                        log.debug("Copied " + testPath + " to " + copiedFile);
                        Files.delete(testPath);
index 4ec456b34d46054ad898728a84b0d21180a2adb4..287727544cb92d56a97f92194d85ee48b3e28a1a 100644 (file)
@@ -2,6 +2,7 @@ package org.argeo.cms.ssh.cli;
 
 import org.argeo.api.cli.CommandsCli;
 
+/** SSH command line interface. */
 public class SshCli extends CommandsCli {
        public SshCli(String commandName) {
                super(commandName);
index eadefa593d237725405e24e516b4d9971237dce5..852cb522158d95ab18b727e8b444be60ad68eb2b 100644 (file)
@@ -12,12 +12,11 @@ import org.apache.batik.transcoder.TranscoderInput;
 import org.apache.batik.transcoder.TranscoderOutput;
 import org.apache.batik.transcoder.image.ImageTranscoder;
 import org.apache.batik.transcoder.image.PNGTranscoder;
-import org.apache.commons.io.FilenameUtils;
 
 public class SvgToPng {
 
        public void convertSvgDir(Path sourceDir, Path targetDir, int width) {
-               System.out.println("##\n## " + width + "px - " + sourceDir+"\n##");
+               System.out.println("##\n## " + width + "px - " + sourceDir + "\n##");
                try {
                        if (targetDir == null)
                                targetDir = sourceDir.getParent().resolve(Integer.toString(width));
@@ -30,7 +29,8 @@ public class SvgToPng {
                        transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) width);
 
                        for (Path source : Files.newDirectoryStream(sourceDir, "*.svg")) {
-                               String baseName = FilenameUtils.getBaseName(source.toString());
+                               // FIXME extract base name
+                               String baseName = null; // = FilenameUtils.getBaseName(source.toString());
                                Path target = targetDir.resolve(baseName + ".png");
                                convertSvgFile(transcoder, source, target);
                        }
index 916cc74f2feb4c8bef5f9d3cb2be460e3f549d17..087b4ff7c725116eb8fe4f8be1b5536d9bb23681 100644 (file)
@@ -5,7 +5,7 @@ import org.argeo.api.acr.ContentRepository;
 import org.argeo.api.acr.ContentSession;
 import org.argeo.api.cms.ux.Cms2DSize;
 import org.argeo.api.cms.ux.CmsView;
-import org.argeo.util.CurrentSubject;
+import org.argeo.cms.util.CurrentSubject;
 
 public class CmsUxUtils {
        public static ContentSession getContentSession(ContentRepository contentRepository, CmsView cmsView) {
index 43a4034159034cc8565e59aad94d54d42ab6b5d6..baaa25238ebb0f39a33871cbb67ab99270ddb8ea 100644 (file)
@@ -5,11 +5,10 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.argeo.api.acr.Content;
-import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.cms.ux.widgets.AbstractDataPart;
+import org.argeo.cms.ux.widgets.AbstractHierarchicalPart;
 import org.argeo.cms.ux.widgets.HierarchicalPart;
 
-public class ContentHierarchicalPart extends AbstractDataPart<Content, Content> implements HierarchicalPart<Content> {
+public class ContentHierarchicalPart extends AbstractHierarchicalPart<Content> implements HierarchicalPart<Content> {
        @Override
        public List<Content> getChildren(Content content) {
                List<Content> res = new ArrayList<>();
@@ -27,14 +26,4 @@ public class ContentHierarchicalPart extends AbstractDataPart<Content, Content>
        protected boolean isLeaf(Content content) {
                return false;
        }
-
-       @Override
-       public String getText(Content model) {
-               try {
-                       return NamespaceUtils.toPrefixedName(model.getName());
-               } catch (IllegalStateException e) {
-                       return model.getName().toString();
-               }
-       }
-
 }
diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/AbstractColumnsPart.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/AbstractColumnsPart.java
new file mode 100644 (file)
index 0000000..143b9cc
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.cms.ux.widgets;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class AbstractColumnsPart<INPUT, TYPE> extends AbstractDataPart<INPUT, TYPE> implements ColumnsPart<INPUT, TYPE> {
+
+       private List<Column<TYPE>> columns = new ArrayList<>();
+
+       @Override
+       public Column<TYPE> getColumn(int index) {
+               if (index >= columns.size())
+                       throw new IllegalArgumentException("There a only " + columns.size());
+               return columns.get(index);
+       }
+
+       @Override
+       public void addColumn(Column<TYPE> column) {
+               columns.add(column);
+       }
+
+       @Override
+       public int getColumnCount() {
+               return columns.size();
+       }
+}
index 958fcde6a32d1fad4306c51753fbd49b5eb4e226..04811af8753199ce6948b63d6651152c038d4955 100644 (file)
@@ -3,12 +3,11 @@ package org.argeo.cms.ux.widgets;
 import java.util.IdentityHashMap;
 import java.util.function.Consumer;
 
-public abstract class AbstractDataPart<INPUT, T> implements DataPart<INPUT, T> {
+public abstract class AbstractDataPart<INPUT, TYPE> implements DataPart<INPUT, TYPE> {
+       private Consumer<TYPE> onSelected;
+       private Consumer<TYPE> onAction;
 
-       private Consumer<T> onSelected;
-       private Consumer<T> onAction;
-
-       private IdentityHashMap<DataView<INPUT, T>, Object> views = new IdentityHashMap<>();
+       private IdentityHashMap<DataView<INPUT, TYPE>, Object> views = new IdentityHashMap<>();
 
        private INPUT data;
 
@@ -24,38 +23,43 @@ public abstract class AbstractDataPart<INPUT, T> implements DataPart<INPUT, T> {
        }
 
        @Override
-       public void onSelected(Consumer<T> onSelected) {
+       public void onSelected(Consumer<TYPE> onSelected) {
                this.onSelected = onSelected;
        }
 
        @Override
-       public void onAction(Consumer<T> onAction) {
+       public void onAction(Consumer<TYPE> onAction) {
                this.onAction = onAction;
        }
 
-       public Consumer<T> getOnSelected() {
+       public Consumer<TYPE> getOnSelected() {
                return onSelected;
        }
 
-       public Consumer<T> getOnAction() {
+       public Consumer<TYPE> getOnAction() {
                return onAction;
        }
 
        @Override
        public void refresh() {
-               for (DataView<INPUT, T> view : views.keySet()) {
+               for (DataView<INPUT, TYPE> view : views.keySet()) {
                        view.refresh();
                }
        }
 
+       protected void notifyItemCountChange() {
+               for (DataView<INPUT, TYPE> view : views.keySet()) {
+                       view.notifyItemCountChange();
+               }
+       }
+
        @Override
-       public void addView(DataView<INPUT, T> view) {
+       public void addView(DataView<INPUT, TYPE> view) {
                views.put(view, new Object());
        }
 
        @Override
-       public void removeView(DataView<INPUT, T> view) {
+       public void removeView(DataView<INPUT, TYPE> view) {
                views.remove(view);
        }
-
 }
index dd1854d3922be89816b61cb6ef9e952825281e05..ccdcf4ea568977dc3227c93c9ec83267fddfbd48 100644 (file)
@@ -1,5 +1,5 @@
 package org.argeo.cms.ux.widgets;
 
-public abstract class AbstractHierarchicalPart<T> extends AbstractDataPart<T, T> implements HierarchicalPart<T> {
+public abstract class AbstractHierarchicalPart<T> extends AbstractColumnsPart<T, T> implements HierarchicalPart<T> {
 
 }
index 7e63ea85bc7a27b9b77ec83f6ab33bb0c3e6b55e..835bc7ec72f8f18707844bf97eedc0f04b724410 100644 (file)
@@ -1,25 +1,6 @@
 package org.argeo.cms.ux.widgets;
 
-import java.util.ArrayList;
-import java.util.List;
+public abstract class AbstractTabularPart<INPUT, TYPE> extends AbstractColumnsPart<INPUT, TYPE>
+               implements TabularPart<INPUT, TYPE> {
 
-public abstract class AbstractTabularPart<INPUT, T> extends AbstractDataPart<INPUT, T> implements TabularPart<INPUT, T> {
-
-       private List<Column<T>> columns = new ArrayList<>();
-
-       @Override
-       public Column<T> getColumn(int index) {
-               if (index >= columns.size())
-                       throw new IllegalArgumentException("There a only " + columns.size());
-               return columns.get(index);
-       }
-
-       public void addColumn(Column<T> column) {
-               columns.add(column);
-       }
-
-       @Override
-       public int getColumnCount() {
-               return columns.size();
-       }
 }
diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/CmsDialog.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/CmsDialog.java
new file mode 100644 (file)
index 0000000..3b1630d
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.cms.ux.widgets;
+
+public interface CmsDialog {
+
+       // must be the same value as org.eclipse.jface.window.Window#OK
+       int OK = 0;
+       // must be the same value as org.eclipse.jface.window.Window#CANCEL
+       int CANCEL = 1;
+
+}
index 973fddb5a8504a070c2968fe2643e711de6181be..71cd263f89b302f7717a268df44f1788e9c1be28 100644 (file)
@@ -2,14 +2,16 @@ package org.argeo.cms.ux.widgets;
 
 import org.argeo.api.cms.ux.CmsIcon;
 
-public interface Column<T> {
-       String getText(T model);
+/** A column in a data representation. */
+@FunctionalInterface
+public interface Column<TYPE> {
+       String getText(TYPE model);
 
        default int getWidth() {
                return 200;
        }
 
-       default CmsIcon getIcon(T model) {
+       default CmsIcon getIcon(TYPE model) {
                return null;
        }
 
index a60401c1fc0d0ceb8923a3d5797d3a8c86f21981..2aaeb49de46200a66fb757b8969b02f41345a0b6 100644 (file)
@@ -1,5 +1,12 @@
 package org.argeo.cms.ux.widgets;
 
+/** A presentation of data in columns. */
 public interface ColumnsPart<INPUT, TYPE> extends DataPart<INPUT, TYPE> {
 
+       Column<TYPE> getColumn(int index);
+
+       void addColumn(Column<TYPE> column);
+
+       int getColumnCount();
+
 }
index 11a12cf7bfc77cf83bb41093cf25e464b883fc2e..9d3ca33ff1ab6e046904b1abe3327483de1788b5 100644 (file)
@@ -2,22 +2,27 @@ package org.argeo.cms.ux.widgets;
 
 import java.util.function.Consumer;
 
-public interface DataPart<INPUT, T> {
+public interface DataPart<INPUT, TYPE> {
        void setInput(INPUT data);
 
        INPUT getInput();
 
-       void onSelected(Consumer<T> onSelected);
+       void onSelected(Consumer<TYPE> onSelected);
 
-       Consumer<T> getOnSelected();
+       Consumer<TYPE> getOnSelected();
 
-       void onAction(Consumer<T> onAction);
+       void onAction(Consumer<TYPE> onAction);
 
-       Consumer<T> getOnAction();
+       Consumer<TYPE> getOnAction();
 
        void refresh();
 
-       void addView(DataView<INPUT, T> view);
+       void addView(DataView<INPUT, TYPE> view);
+
+       void removeView(DataView<INPUT, TYPE> view);
+
+//     void select(TYPE data);
+//
+//     TYPE getSelected();
 
-       void removeView(DataView<INPUT, T> view);
 }
index 9768c68ec9a94e9feeb5cd006c48ec5f2bbd674b..311cf924ed74e265b231bab09f2eee855389277b 100644 (file)
@@ -2,4 +2,6 @@ package org.argeo.cms.ux.widgets;
 
 public interface DataView<INPUT,TYPE> {
        void refresh();
+       
+       void notifyItemCountChange();
 }
index 372c295dcfb34c34cf44bfbfe4efd14743037c5a..8f0e798453673b9a1497a7390af41a43a845b33d 100644 (file)
@@ -2,15 +2,7 @@ package org.argeo.cms.ux.widgets;
 
 import java.util.List;
 
-import org.argeo.api.cms.ux.CmsIcon;
-
+/** A hierarchical representation of data. */
 public interface HierarchicalPart<T> extends ColumnsPart<T, T> {
        List<T> getChildren(T parent);
-
-       String getText(T model);
-
-       default CmsIcon getIcon(T model) {
-               return null;
-       }
-
 }
index 6adc0c3e6c1ffdf37c47c97a62793611aaec4765..01b4d6b6b664d60b72f37c18056953e67691d2f0 100644 (file)
@@ -1,11 +1,8 @@
 package org.argeo.cms.ux.widgets;
 
-public interface TabularPart<INPUT, T> extends ColumnsPart<INPUT, T> {
+/** A tabular presentation of data. */
+public interface TabularPart<INPUT, TYPE> extends ColumnsPart<INPUT, TYPE> {
        int getItemCount();
 
-       T getData(int row);
-
-       Column<T> getColumn(int index);
-
-       int getColumnCount();
+       TYPE getData(int row);
 }
diff --git a/org.argeo.cms/META-INF/native-image/jni-config.json b/org.argeo.cms/META-INF/native-image/jni-config.json
deleted file mode 100644 (file)
index 25530bb..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-[
-{
-  "name":"java.lang.Boolean",
-  "methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.ClassLoader",
-  "methods":[
-    {"name":"getPlatformClassLoader","parameterTypes":[] }, 
-    {"name":"loadClass","parameterTypes":["java.lang.String"] }
-  ]
-},
-{
-  "name":"jdk.internal.loader.ClassLoaders$PlatformClassLoader"
-},
-{
-  "name":"org.graalvm.jniutils.JNIExceptionWrapperEntryPoints",
-  "methods":[{"name":"getClassName","parameterTypes":["java.lang.Class"] }]
-},
-{
-  "name":"sun.management.VMManagementImpl",
-  "fields":[
-    {"name":"compTimeMonitoringSupport"}, 
-    {"name":"currentThreadCpuTimeSupport"}, 
-    {"name":"objectMonitorUsageSupport"}, 
-    {"name":"otherThreadCpuTimeSupport"}, 
-    {"name":"remoteDiagnosticCommandsSupport"}, 
-    {"name":"synchronizerUsageSupport"}, 
-    {"name":"threadAllocatedMemorySupport"}, 
-    {"name":"threadContentionMonitoringSupport"}
-  ]
-}
-]
diff --git a/org.argeo.cms/META-INF/native-image/predefined-classes-config.json b/org.argeo.cms/META-INF/native-image/predefined-classes-config.json
deleted file mode 100644 (file)
index 0e79b2c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-[
-  {
-    "type":"agent-extracted",
-    "classes":[
-    ]
-  }
-]
-
diff --git a/org.argeo.cms/META-INF/native-image/proxy-config.json b/org.argeo.cms/META-INF/native-image/proxy-config.json
deleted file mode 100644 (file)
index 0d4f101..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[
-]
diff --git a/org.argeo.cms/META-INF/native-image/reflect-config.json b/org.argeo.cms/META-INF/native-image/reflect-config.json
deleted file mode 100644 (file)
index 2c9df69..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-[
-{
-  "name":"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"java.security.SecureRandomParameters"
-},
-{
-  "name":"javax.security.auth.login.Configuration$Parameters"
-},
-{
-  "name":"org.apache.xerces.impl.dv.dtd.DTDDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.dv.dtd.XML11DTDDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.dv.xs.ExtendedSchemaDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.xs.XSMessageFormatter",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.parsers.XIncludeAwareParserConfiguration",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.argeo.cms.auth.DataAdminLoginModule",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.ConfigFile$Spi",
-  "methods":[{"name":"<init>","parameterTypes":["javax.security.auth.login.Configuration$Parameters"] }]
-},
-{
-  "name":"sun.security.provider.DRBG",
-  "methods":[{"name":"<init>","parameterTypes":["java.security.SecureRandomParameters"] }]
-},
-{
-  "name":"sun.security.provider.NativePRNG",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.SHA",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.SHA2$SHA256",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-}
-]
diff --git a/org.argeo.cms/META-INF/native-image/resource-config.json b/org.argeo.cms/META-INF/native-image/resource-config.json
deleted file mode 100644 (file)
index d5f778e..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-  "resources":{
-  "includes":[
-    {
-      "pattern":"\\QMETA-INF/services/javax.xml.validation.SchemaFactory\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/DSMLv2.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/SVG.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/XForms-11-Schema.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/XMLSchema.dtd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/XMLSchema.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/cr.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/datatypes.dtd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/docbook.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/schema-for-xslt20.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/xlink.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/xml-events-attribs-1.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/xml.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/internal/runtime/jaas.cfg\\E"
-    }
-  ]},
-  "bundles":[
-    {
-      "name":"org.apache.xerces.impl.msg.XMLSchemaMessages",
-      "locales":[
-        "en", 
-        "und"
-      ]
-    }, 
-    {
-      "name":"org.apache.xerces.impl.xpath.regex.message",
-      "locales":[
-        "", 
-        "en", 
-        "und"
-      ]
-    }, 
-    {
-      "name":"sun.security.util.Resources",
-      "classNames":["sun.security.util.Resources"]
-    }
-  ]
-}
diff --git a/org.argeo.cms/META-INF/native-image/serialization-config.json b/org.argeo.cms/META-INF/native-image/serialization-config.json
deleted file mode 100644 (file)
index bf554e0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "types":[
-  ],
-  "lambdaCapturingTypes":[
-  ]
-}
index 6b05a900445c9fe94c0372688b87444a5ccc892b..afd4e0aaf06f6f559301c717226df04ca78cf6e6 100644 (file)
@@ -4,6 +4,6 @@
    <service>
       <provide interface="com.sun.net.httpserver.HttpHandler"/>
    </service>
-   <property name="context.path" type="String" value="/api/acr" />
+   <property name="context.path" type="String" value="/api/acr/" />
    <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.spi.ProvidedRepository" name="ProvidedRepository" policy="static"/>
 </scr:component>
index b7a13b4d10041b5d1399831ec51a409fbb5ac298..306717b1c24fdaed17065ef18760ac352bc6380e 100644 (file)
@@ -8,5 +8,5 @@
    </service>
    <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
    <reference bind="setUuidFactory" cardinality="1..1" interface="org.argeo.api.uuid.UuidFactory" name="UuidFactory" policy="static"/>
-   <reference bind="setUserManager" cardinality="1..1" interface="org.argeo.cms.CmsUserManager" name="CmsUserManager" policy="static"/>
+   <reference bind="setUserManager" cardinality="1..1" interface="org.argeo.api.cms.directory.CmsUserManager" name="CmsUserManager" policy="static"/>
 </scr:component>
index 50a9ea6eb791c1f399d6948fc66ee6edaa4cff85..52c75318e044ed5a4ef713b0dbb0a6adfedd75b1 100644 (file)
@@ -2,8 +2,8 @@
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" immediate="false" name="Node User Admin">
    <implementation class="org.argeo.cms.internal.runtime.CmsUserAdmin"/>
    <property name="service.pid" type="String" value="org.argeo.api.userAdmin"/>
-   <reference bind="setTransactionManager" cardinality="1..1" interface="org.argeo.util.transaction.WorkControl" name="WorkControl" policy="static"/>
-   <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.util.transaction.WorkTransaction" name="WorkTransaction" policy="static"/>
+   <reference bind="setTransactionManager" cardinality="1..1" interface="org.argeo.api.cms.transaction.WorkControl" name="WorkControl" policy="static"/>
+   <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.api.cms.transaction.WorkTransaction" name="WorkTransaction" policy="static"/>
  <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
  <service>
     <provide interface="org.osgi.service.useradmin.UserAdmin"/>
index d22660c9fc57034a6bb9345e6eee6b65fe428f52..d76c89a1b858d4e1e5f145ba31ae1674817dc05c 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" immediate="true" name="User Admin Service">
-   <implementation class="org.argeo.cms.internal.auth.CmsUserManagerImpl"/>
+   <implementation class="org.argeo.cms.internal.runtime.CmsUserManagerImpl"/>
    <service>
-      <provide interface="org.argeo.cms.CmsUserManager"/>
+      <provide interface="org.argeo.api.cms.directory.CmsUserManager"/>
    </service>
    <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
-   <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.util.transaction.WorkTransaction" name="UserTransaction" policy="static"/>
+   <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.api.cms.transaction.WorkTransaction" name="UserTransaction" policy="static"/>
 </scr:component>
index 81997476eece13220a0333f669dfc7b1d451fa21..df317e937f97b1ed24cf1cc3ed5492410edf7950 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Simple Transaction Manager">
-   <implementation class="org.argeo.util.transaction.SimpleTransactionManager"/>
+   <implementation class="org.argeo.api.cms.transaction.SimpleTransactionManager"/>
    <service>
-      <provide interface="org.argeo.util.transaction.WorkControl"/>
-      <provide interface="org.argeo.util.transaction.WorkTransaction"/>
+      <provide interface="org.argeo.api.cms.transaction.WorkControl"/>
+      <provide interface="org.argeo.api.cms.transaction.WorkTransaction"/>
    </service>
 </scr:component>
diff --git a/org.argeo.cms/src/org/argeo/cms/AbstractKeyring.java b/org.argeo.cms/src/org/argeo/cms/AbstractKeyring.java
new file mode 100644 (file)
index 0000000..c2c9c61
--- /dev/null
@@ -0,0 +1,290 @@
+package org.argeo.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.keyring.PBEKeySpecCallback;
+import org.argeo.cms.util.CurrentSubject;
+import org.argeo.cms.util.StreamUtils;
+import org.argeo.api.cms.keyring.CryptoKeyring;
+import org.argeo.api.cms.keyring.Keyring;
+
+/** username / password based keyring. TODO internationalize */
+public abstract class AbstractKeyring implements Keyring, CryptoKeyring {
+       // public final static String DEFAULT_KEYRING_LOGIN_CONTEXT = "KEYRING";
+
+       // private String loginContextName = DEFAULT_KEYRING_LOGIN_CONTEXT;
+       private CallbackHandler defaultCallbackHandler;
+
+       private String charset = "UTF-8";
+
+       /**
+        * Default provider is bouncy castle, in order to have consistent behaviour
+        * across implementations
+        */
+       private String securityProviderName = "BC";
+
+       /**
+        * Whether the keyring has already been created in the past with a master
+        * password
+        */
+       protected abstract Boolean isSetup();
+
+       /**
+        * Setup the keyring persistently, {@link #isSetup()} must return true
+        * afterwards
+        */
+       protected abstract void setup(char[] password);
+
+       /** Populates the key spec callback */
+       protected abstract void handleKeySpecCallback(PBEKeySpecCallback pbeCallback);
+
+       protected abstract void encrypt(String path, InputStream unencrypted);
+
+       protected abstract InputStream decrypt(String path);
+
+       /** Triggers lazy initialization */
+       protected SecretKey getSecretKey(char[] password) {
+               Subject subject = CurrentSubject.current();
+               if (subject == null)
+                       throw new IllegalStateException("Current subject cannot be null");
+               // we assume only one secrete key is available
+               Iterator<SecretKey> iterator = subject.getPrivateCredentials(SecretKey.class).iterator();
+               if (!iterator.hasNext() || password != null) {// not initialized
+                       CallbackHandler callbackHandler = password == null ? new KeyringCallbackHandler()
+                                       : new PasswordProvidedCallBackHandler(password);
+                       ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
+                       Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+                       try {
+                               LoginContext loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_KEYRING, subject, callbackHandler);
+                               loginContext.login();
+                               // FIXME will login even if password is wrong
+                               iterator = subject.getPrivateCredentials(SecretKey.class).iterator();
+                               return iterator.next();
+                       } catch (LoginException e) {
+                               throw new IllegalStateException("Keyring login failed", e);
+                       } finally {
+                               Thread.currentThread().setContextClassLoader(currentContextClassLoader);
+                       }
+
+               } else {
+                       SecretKey secretKey = iterator.next();
+                       if (iterator.hasNext())
+                               throw new IllegalStateException("More than one secret key in private credentials");
+                       return secretKey;
+               }
+       }
+
+       public InputStream getAsStream(String path) {
+               return decrypt(path);
+       }
+
+       public void set(String path, InputStream in) {
+               encrypt(path, in);
+       }
+
+       public char[] getAsChars(String path) {
+               // InputStream in = getAsStream(path);
+               // CharArrayWriter writer = null;
+               // Reader reader = null;
+               try (InputStream in = getAsStream(path);
+                               CharArrayWriter writer = new CharArrayWriter();
+                               Reader reader = new InputStreamReader(in, charset);) {
+                       StreamUtils.copy(reader, writer);
+                       return writer.toCharArray();
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot decrypt to char array", e);
+               } finally {
+                       // IOUtils.closeQuietly(reader);
+                       // IOUtils.closeQuietly(in);
+                       // IOUtils.closeQuietly(writer);
+               }
+       }
+
+       public void set(String path, char[] arr) {
+               // ByteArrayOutputStream out = new ByteArrayOutputStream();
+               // ByteArrayInputStream in = null;
+               // Writer writer = null;
+               try (ByteArrayOutputStream out = new ByteArrayOutputStream();
+                               Writer writer = new OutputStreamWriter(out, charset);) {
+                       // writer = new OutputStreamWriter(out, charset);
+                       writer.write(arr);
+                       writer.flush();
+                       // in = new ByteArrayInputStream(out.toByteArray());
+                       try (ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());) {
+                               set(path, in);
+                       }
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot encrypt to char array", e);
+               } finally {
+                       // IOUtils.closeQuietly(writer);
+                       // IOUtils.closeQuietly(out);
+                       // IOUtils.closeQuietly(in);
+               }
+       }
+
+       public void unlock(char[] password) {
+               if (!isSetup())
+                       setup(password);
+               SecretKey secretKey = getSecretKey(password);
+               if (secretKey == null)
+                       throw new IllegalStateException("Could not unlock keyring");
+       }
+
+       protected Provider getSecurityProvider() {
+               return Security.getProvider(securityProviderName);
+       }
+
+       public void setDefaultCallbackHandler(CallbackHandler defaultCallbackHandler) {
+               this.defaultCallbackHandler = defaultCallbackHandler;
+       }
+
+       public void setCharset(String charset) {
+               this.charset = charset;
+       }
+
+       public void setSecurityProviderName(String securityProviderName) {
+               this.securityProviderName = securityProviderName;
+       }
+
+       // @Deprecated
+       // protected static byte[] hash(char[] password, byte[] salt, Integer
+       // iterationCount) {
+       // ByteArrayOutputStream out = null;
+       // OutputStreamWriter writer = null;
+       // try {
+       // out = new ByteArrayOutputStream();
+       // writer = new OutputStreamWriter(out, "UTF-8");
+       // writer.write(password);
+       // MessageDigest pwDigest = MessageDigest.getInstance("SHA-256");
+       // pwDigest.reset();
+       // pwDigest.update(salt);
+       // byte[] btPass = pwDigest.digest(out.toByteArray());
+       // for (int i = 0; i < iterationCount; i++) {
+       // pwDigest.reset();
+       // btPass = pwDigest.digest(btPass);
+       // }
+       // return btPass;
+       // } catch (Exception e) {
+       // throw new CmsException("Cannot hash", e);
+       // } finally {
+       // IOUtils.closeQuietly(out);
+       // IOUtils.closeQuietly(writer);
+       // }
+       //
+       // }
+
+       /**
+        * Convenience method using the underlying callback to ask for a password
+        * (typically used when the password is not saved in the keyring)
+        */
+       protected char[] ask() {
+               PasswordCallback passwordCb = new PasswordCallback("Password", false);
+               Callback[] dialogCbs = new Callback[] { passwordCb };
+               try {
+                       defaultCallbackHandler.handle(dialogCbs);
+                       char[] password = passwordCb.getPassword();
+                       return password;
+               } catch (Exception e) {
+                       throw new IllegalStateException("Cannot ask for a password", e);
+               }
+
+       }
+
+       class KeyringCallbackHandler implements CallbackHandler {
+               public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                       // checks
+                       if (callbacks.length != 2)
+                               throw new IllegalArgumentException(
+                                               "Keyring requires 2 and only 2 callbacks: {PasswordCallback,PBEKeySpecCallback}");
+                       if (!(callbacks[0] instanceof PasswordCallback))
+                               throw new UnsupportedCallbackException(callbacks[0]);
+                       if (!(callbacks[1] instanceof PBEKeySpecCallback))
+                               throw new UnsupportedCallbackException(callbacks[0]);
+
+                       PasswordCallback passwordCb = (PasswordCallback) callbacks[0];
+                       PBEKeySpecCallback pbeCb = (PBEKeySpecCallback) callbacks[1];
+
+                       if (isSetup()) {
+                               Callback[] dialogCbs = new Callback[] { passwordCb };
+                               defaultCallbackHandler.handle(dialogCbs);
+                       } else {// setup keyring
+                               TextOutputCallback textCb1 = new TextOutputCallback(TextOutputCallback.INFORMATION,
+                                               "Enter a master password which will protect your private data");
+                               TextOutputCallback textCb2 = new TextOutputCallback(TextOutputCallback.INFORMATION,
+                                               "(for example your credentials to third-party services)");
+                               TextOutputCallback textCb3 = new TextOutputCallback(TextOutputCallback.INFORMATION,
+                                               "Don't forget this password since the data cannot be read without it");
+                               PasswordCallback confirmPasswordCb = new PasswordCallback("Confirm password", false);
+                               // first try
+                               Callback[] dialogCbs = new Callback[] { textCb1, textCb2, textCb3, passwordCb, confirmPasswordCb };
+                               defaultCallbackHandler.handle(dialogCbs);
+
+                               // if passwords different, retry (except if cancelled)
+                               while (passwordCb.getPassword() != null
+                                               && !Arrays.equals(passwordCb.getPassword(), confirmPasswordCb.getPassword())) {
+                                       TextOutputCallback textCb = new TextOutputCallback(TextOutputCallback.ERROR,
+                                                       "The passwords do not match");
+                                       dialogCbs = new Callback[] { textCb, passwordCb, confirmPasswordCb };
+                                       defaultCallbackHandler.handle(dialogCbs);
+                               }
+
+                               if (passwordCb.getPassword() != null) {// not cancelled
+                                       setup(passwordCb.getPassword());
+                               }
+                       }
+
+                       if (passwordCb.getPassword() != null)
+                               handleKeySpecCallback(pbeCb);
+               }
+
+       }
+
+       class PasswordProvidedCallBackHandler implements CallbackHandler {
+               private final char[] password;
+
+               public PasswordProvidedCallBackHandler(char[] password) {
+                       this.password = password;
+               }
+
+               @Override
+               public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                       // checks
+                       if (callbacks.length != 2)
+                               throw new IllegalArgumentException(
+                                               "Keyring requires 2 and only 2 callbacks: {PasswordCallback,PBEKeySpecCallback}");
+                       if (!(callbacks[0] instanceof PasswordCallback))
+                               throw new UnsupportedCallbackException(callbacks[0]);
+                       if (!(callbacks[1] instanceof PBEKeySpecCallback))
+                               throw new UnsupportedCallbackException(callbacks[0]);
+
+                       PasswordCallback passwordCb = (PasswordCallback) callbacks[0];
+                       passwordCb.setPassword(password);
+                       PBEKeySpecCallback pbeCb = (PBEKeySpecCallback) callbacks[1];
+                       handleKeySpecCallback(pbeCb);
+               }
+
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/CmsUserManager.java b/org.argeo.cms/src/org/argeo/cms/CmsUserManager.java
deleted file mode 100644 (file)
index 728884b..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-package org.argeo.cms;
-
-import java.time.ZonedDateTime;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.security.auth.Subject;
-
-import org.argeo.cms.auth.SystemRole;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.argeo.util.directory.HierarchyUnit;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-
-/**
- * Provide method interfaces to manage user concepts without accessing directly
- * the userAdmin.
- */
-public interface CmsUserManager {
-       Map<String, String> getKnownBaseDns(boolean onlyWritable);
-
-       Set<UserDirectory> getUserDirectories();
-
-       // CurrentUser
-       /** Returns the e-mail of the current logged in user */
-       String getMyMail();
-
-       // Other users
-       /** Returns a {@link User} given a username */
-       User getUser(String username);
-
-       /** Can be a group or a user */
-       String getUserDisplayName(String dn);
-
-       /** Can be a group or a user */
-       String getUserMail(String dn);
-
-       /** Lists all roles of the given user */
-       String[] getUserRoles(String dn);
-
-       /** Checks if the passed user belongs to the passed role */
-       boolean isUserInRole(String userDn, String roleDn);
-
-       // Search
-       /** Returns a filtered list of roles */
-       Role[] getRoles(String filter) throws InvalidSyntaxException;
-
-       /** Recursively lists users in a given group. */
-       Set<User> listUsersInGroup(String groupDn, String filter);
-
-       /** Search among groups including system roles and users if needed */
-       List<User> listGroups(String filter, boolean includeUsers, boolean includeSystemRoles);
-
-//     /**
-//      * Lists functional accounts, that is users with regular access to the system
-//      * under this functional hierarchy unit (which probably have technical direct
-//      * sub hierarchy units), excluding groups which are not explicitly users.
-//      */
-//     Set<User> listAccounts(HierarchyUnit hierarchyUnit, boolean deep);
-
-       /*
-        * EDITION
-        */
-       /** Creates a new user. */
-       User createUser(String username, Map<String, Object> properties, Map<String, Object> credentials);
-
-       /** Creates a group. */
-       Group getOrCreateGroup(HierarchyUnit groups, String commonName);
-
-       /** Creates a new system role. */
-       Group getOrCreateSystemRole(HierarchyUnit roles, SystemRole systemRole);
-
-       /** Add additional object classes to this role. */
-       void addObjectClasses(Role role, Set<String> objectClasses, Map<String, Object> additionalProperties);
-
-       /** Add additional object classes to this hierarchy unit. */
-       void addObjectClasses(HierarchyUnit hierarchyUnit, Set<String> objectClasses,
-                       Map<String, Object> additionalProperties);
-
-       /** Add a member to this group. */
-       void addMember(Group group, Role role);
-       
-       void edit(Runnable action);
-
-       /* MISCELLANEOUS */
-       /** Returns the dn of a role given its local ID */
-       String buildDefaultDN(String localId, int type);
-
-       /** Exposes the main default domain name for this instance */
-       String getDefaultDomainName();
-
-       /**
-        * Search for a {@link User} (might also be a group) whose uid or cn is equals
-        * to localId within the various user repositories defined in the current
-        * context.
-        */
-       User getUserFromLocalId(String localId);
-
-       void changeOwnPassword(char[] oldPassword, char[] newPassword);
-
-       void resetPassword(String username, char[] newPassword);
-
-       @Deprecated
-       String addSharedSecret(String username, int hours);
-
-//     String addSharedSecret(String username, String authInfo, String authToken);
-
-       void addAuthToken(String userDn, String token, Integer hours, String... roles);
-
-       void addAuthToken(String userDn, String token, ZonedDateTime expiryDate, String... roles);
-
-       void expireAuthToken(String token);
-
-       void expireAuthTokens(Subject subject);
-
-       UserDirectory getDirectory(Role role);
-
-       /** Create a new hierarchy unit. Does nothing if it already exists. */
-       HierarchyUnit getOrCreateHierarchyUnit(UserDirectory directory, String path);
-}
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/CurrentUser.java b/org.argeo.cms/src/org/argeo/cms/CurrentUser.java
new file mode 100644 (file)
index 0000000..ad12a86
--- /dev/null
@@ -0,0 +1,187 @@
+package org.argeo.cms;
+
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.security.auth.Subject;
+import javax.security.auth.x500.X500Principal;
+
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsSession;
+import org.argeo.api.cms.CmsSessionId;
+import org.argeo.cms.internal.auth.CmsSessionImpl;
+import org.argeo.cms.internal.auth.ImpliedByPrincipal;
+import org.argeo.cms.internal.runtime.CmsContextImpl;
+import org.argeo.cms.util.CurrentSubject;
+import org.osgi.service.useradmin.Authorization;
+
+/**
+ * Programmatic access to the currently authenticated user, within a CMS
+ * context.
+ */
+public final class CurrentUser {
+       /**
+        * Technical username of the currently authenticated user.
+        * 
+        * @return the authenticated username or null if not authenticated / anonymous
+        */
+       public static String getUsername() {
+               return getUsername(currentSubject());
+       }
+
+       /**
+        * Human readable name of the currently authenticated user (typically first name
+        * and last name).
+        */
+       public static String getDisplayName() {
+               return getDisplayName(currentSubject());
+       }
+
+       /** Whether a user is currently authenticated. */
+       public static boolean isAnonymous() {
+               return isAnonymous(currentSubject());
+       }
+
+       /** Locale of the current user */
+       public static Locale locale() {
+               return locale(currentSubject());
+       }
+
+       /** Roles of the currently logged-in user */
+       public static Set<String> roles() {
+               return roles(currentSubject());
+       }
+
+       /** Returns true if the current user is in the specified role */
+       public static boolean isInRole(String role) {
+               Set<String> roles = roles();
+               return roles.contains(role);
+       }
+
+       /** Implies this {@link SystemRole} in this context. */
+       public static boolean implies(SystemRole role, String context) {
+               return role.implied(currentSubject(), context);
+       }
+
+       /** Implies this role name, also independently of the context. */
+       public static boolean implies(String role, String context) {
+               return SystemRole.implied(NamespaceUtils.parsePrefixedName(role), currentSubject(), context);
+       }
+
+       /** Get the primary context this user belongs to. */
+       public static boolean isUserContext(String context) {
+               // TODO have the role context as a separated credential in the Subjecto?
+               return RoleNameUtils.getContext(getUsername()).equalsIgnoreCase(context);
+       }
+
+       /** Executes as the current user */
+       public static <T> T doAs(PrivilegedAction<T> action) {
+               return Subject.doAs(currentSubject(), action);
+       }
+
+       /** Executes as the current user */
+       public static <T> T tryAs(PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
+               return Subject.doAs(currentSubject(), action);
+       }
+
+       /*
+        * WRAPPERS
+        */
+
+       public static String getUsername(Subject subject) {
+               if (subject == null)
+                       throw new IllegalArgumentException("Subject cannot be null");
+               if (subject.getPrincipals(X500Principal.class).size() != 1)
+                       return CmsConstants.ROLE_ANONYMOUS;
+               Principal principal = subject.getPrincipals(X500Principal.class).iterator().next();
+               return principal.getName();
+       }
+
+       public static String getDisplayName(Subject subject) {
+               return getAuthorization(subject).toString();
+       }
+
+       public static Set<String> roles(Subject subject) {
+               Set<String> roles = new HashSet<String>();
+               roles.add(getUsername(subject));
+               for (Principal group : subject.getPrincipals(ImpliedByPrincipal.class)) {
+                       roles.add(group.getName());
+               }
+               return roles;
+       }
+
+       public static Locale locale(Subject subject) {
+               Set<Locale> locales = subject.getPublicCredentials(Locale.class);
+               if (locales.isEmpty()) {
+                       Locale defaultLocale = CmsContextImpl.getCmsContext().getDefaultLocale();
+                       return defaultLocale;
+               } else
+                       return locales.iterator().next();
+       }
+
+       /** Whether this user is currently authenticated. */
+       public static boolean isAnonymous(Subject subject) {
+               if (subject == null)
+                       return true;
+               String username = getUsername(subject);
+               return username == null || username.equalsIgnoreCase(CmsConstants.ROLE_ANONYMOUS);
+       }
+
+       public static CmsSession getCmsSession() {
+               Subject subject = currentSubject();
+               Iterator<CmsSessionId> it = subject.getPrivateCredentials(CmsSessionId.class).iterator();
+               if (!it.hasNext())
+                       throw new IllegalStateException("No CMS session id available for " + subject);
+               CmsSessionId cmsSessionId = it.next();
+               if (it.hasNext())
+                       throw new IllegalStateException("More than one CMS session id available for " + subject);
+               return CmsContextImpl.getCmsContext().getCmsSessionByUuid(cmsSessionId.getUuid());
+       }
+
+       public static boolean isAvailable() {
+               return CurrentSubject.current() != null;
+       }
+
+       /*
+        * HELPERS
+        */
+       private static Subject currentSubject() {
+               Subject subject = CurrentSubject.current();
+               if (subject == null)
+                       throw new IllegalStateException("Cannot find related subject");
+               return subject;
+       }
+
+       private static Authorization getAuthorization(Subject subject) {
+               return subject.getPrivateCredentials(Authorization.class).iterator().next();
+       }
+
+       public static boolean logoutCmsSession(Subject subject) {
+               UUID nodeSessionId;
+               if (subject.getPrivateCredentials(CmsSessionId.class).size() == 1)
+                       nodeSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next().getUuid();
+               else
+                       return false;
+               CmsSessionImpl cmsSession = CmsContextImpl.getCmsContext().getCmsSessionByUuid(nodeSessionId);
+
+               // FIXME logout all views
+               // TODO check why it is sometimes null
+               if (cmsSession != null)
+                       cmsSession.close();
+               // if (log.isDebugEnabled())
+               // log.debug("Logged out CMS session " + cmsSession.getUuid());
+               return true;
+       }
+
+       /** singleton */
+       private CurrentUser() {
+       }
+}
index 4bfda139d686345f261dd9675de1c500b9cb2eda..8aca8768a04d9e3af196ce9690ea449ba1d7d651 100644 (file)
@@ -4,7 +4,6 @@ import java.util.Locale;
 import java.util.ResourceBundle;
 
 import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.auth.CurrentUser;
 
 /** Utilities simplifying the development of localization enums. */
 public class LocaleUtils {
diff --git a/org.argeo.cms/src/org/argeo/cms/RoleNameUtils.java b/org.argeo.cms/src/org/argeo/cms/RoleNameUtils.java
new file mode 100644 (file)
index 0000000..04302c4
--- /dev/null
@@ -0,0 +1,41 @@
+package org.argeo.cms;
+
+import static org.argeo.api.acr.RuntimeNamespaceContext.getNamespaceContext;
+
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.ArgeoNamespace;
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.cms.directory.ldap.LdapNameUtils;
+
+/** Simplifies analysis of system roles. */
+public class RoleNameUtils {
+       public static String getLastRdnValue(String dn) {
+               return LdapNameUtils.getLastRdnValue(dn);
+//             // we don't use LdapName for portability with Android
+//             // TODO make it more robust
+//             String[] parts = dn.split(",");
+//             String[] rdn = parts[0].split("=");
+//             return rdn[1];
+       }
+
+       public static QName getLastRdnAsName(String dn) {
+               String cn = getLastRdnValue(dn);
+               QName roleName = NamespaceUtils.parsePrefixedName(getNamespaceContext(), cn);
+               return roleName;
+       }
+
+       public static boolean isSystemRole(QName roleName) {
+               return roleName.getNamespaceURI().equals(ArgeoNamespace.ROLE_NAMESPACE_URI);
+       }
+
+       public static String getParent(String dn) {
+               int index = dn.indexOf(',');
+               return dn.substring(index + 1);
+       }
+
+       /** Up two levels. */
+       public static String getContext(String dn) {
+               return getParent(getParent(dn));
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/SystemRole.java b/org.argeo.cms/src/org/argeo/cms/SystemRole.java
new file mode 100644 (file)
index 0000000..9564399
--- /dev/null
@@ -0,0 +1,48 @@
+package org.argeo.cms;
+
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.xml.namespace.QName;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.internal.auth.ImpliedByPrincipal;
+
+/** A programmatic role. */
+public interface SystemRole {
+       QName qName();
+
+       /** Whether this role is implied for this authenticated user. */
+       default boolean implied(Subject subject, String context) {
+               return implied(qName(), subject, context);
+       }
+
+       /** Whether this role is implied for this distinguished name. */
+       default boolean implied(String dn, String context) {
+               String roleContext = RoleNameUtils.getContext(dn);
+               QName roleName = RoleNameUtils.getLastRdnAsName(dn);
+               return roleContext.equalsIgnoreCase(context) && qName().equals(roleName);
+       }
+
+       /**
+        * Whether this role is implied for this authenticated subject. If context is
+        * <code>null</code>, it is not considered; this should be used to build user
+        * interfaces, but not to authorise.
+        */
+       static boolean implied(QName name, Subject subject, String context) {
+               Set<ImpliedByPrincipal> roles = subject.getPrincipals(ImpliedByPrincipal.class);
+               for (ImpliedByPrincipal role : roles) {
+                       if (role.isSystemRole()) {
+                               if (role.getRoleName().equals(name)) {
+                                       // !! if context is not specified, it is considered irrelevant
+                                       if (context == null)
+                                               return true;
+                                       if (role.getContext().equalsIgnoreCase(context)
+                                                       || role.getContext().equals(CmsConstants.NODE_BASEDN))
+                                               return true;
+                               }
+                       }
+               }
+               return false;
+       }
+}
index ce05dc14c904e41ee5279725f864c346d7d0de94..16f39609e8aafb1c9185dec0a274ef74431cdedf 100644 (file)
@@ -17,7 +17,7 @@ import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedSession;
-import org.argeo.util.LangUtils;
+import org.argeo.cms.util.LangUtils;
 
 /** Partial reference implementation of a {@link ProvidedContent}. */
 public abstract class AbstractContent extends AbstractMap<QName, Object> implements ProvidedContent {
index a2d8069dd26e7c1698ca8884efe828c2c73f10a4..c1f1ef5f3ac2b3d52619f5578365253ec57558b5 100644 (file)
@@ -17,10 +17,12 @@ import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.argeo.api.acr.ArgeoNamespace;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.api.acr.RuntimeNamespaceContext;
+import org.argeo.api.acr.spi.ContentNamespace;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedRepository;
@@ -93,8 +95,9 @@ public abstract class AbstractContentRepository implements ProvidedRepository {
                }
        }
 
-       public void registerTypes(String prefix, String namespaceURI, String schemaSystemId) {
-               typesManager.registerTypes(prefix, namespaceURI, schemaSystemId);
+       @Override
+       public void registerTypes(ContentNamespace... namespaces) {
+               typesManager.registerTypes(namespaces);
        }
 
        /*
@@ -117,7 +120,7 @@ public abstract class AbstractContentRepository implements ProvidedRepository {
 //                             document = dBuilder.parse(inputSource);
 //                     } else {
                        document = dBuilder.newDocument();
-                       Element root = document.createElementNS(CrName.CR_NAMESPACE_URI,
+                       Element root = document.createElementNS(ArgeoNamespace.CR_NAMESPACE_URI,
                                        NamespaceUtils.toPrefixedName(CrName.root.qName()));
 
                        for (String prefix : RuntimeNamespaceContext.getPrefixes().keySet()) {
diff --git a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentNamespace.java b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentNamespace.java
new file mode 100644 (file)
index 0000000..429b759
--- /dev/null
@@ -0,0 +1,85 @@
+package org.argeo.cms.acr;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Objects;
+
+import org.argeo.api.acr.ArgeoNamespace;
+import org.argeo.api.acr.spi.ContentNamespace;
+
+/** Content namespaces supported by CMS. */
+public enum CmsContentNamespace implements ContentNamespace {
+       //
+       // ARGEO
+       //
+       CR(ArgeoNamespace.CR_DEFAULT_PREFIX, ArgeoNamespace.CR_NAMESPACE_URI, "cr.xsd", null),
+       //
+       SLC("slc", "http://www.argeo.org/ns/slc", null, null),
+       //
+       ARGEO("argeo", "http://www.argeo.org/ns/argeo", null, null),
+       //
+       // EXTERNAL
+       //
+       XSD("xs", "http://www.w3.org/2001/XMLSchema", "XMLSchema.xsd", "http://www.w3.org/2001/XMLSchema.xsd"),
+       //
+       XML("xml", "http://www.w3.org/XML/1998/namespace", "xml.xsd", "http://www.w3.org/2001/xml.xsd"),
+       //
+       XLINK("xlink", "http://www.w3.org/1999/xlink", "xlink.xsd", "https://www.w3.org/1999/xlink.xsd"),
+       //
+       WEBDAV("D", "DAV:", null, "https://raw.githubusercontent.com/lookfirst/sardine/master/webdav.xsd"),
+       //
+       XSLT("xsl", "http://www.w3.org/1999/XSL/Transform", "schema-for-xslt20.xsd",
+                       "https://www.w3.org/2007/schema-for-xslt20.xsd"),
+       //
+       SVG("svg", "http://www.w3.org/2000/svg", "SVG.xsd",
+                       "https://raw.githubusercontent.com/oreillymedia/HTMLBook/master/schema/svg/SVG.xsd"),
+       //
+       DSML("dsml", "urn:oasis:names:tc:DSML:2:0:core", "DSMLv2.xsd",
+                       "https://www.oasis-open.org/committees/dsml/docs/DSMLv2.xsd"),
+       //
+       ;
+
+       private final static String RESOURCE_BASE = "/org/argeo/cms/acr/schemas/";
+
+       private String defaultPrefix;
+       private String namespace;
+       private URL resource;
+       private URL publicUrl;
+
+       CmsContentNamespace(String defaultPrefix, String namespace, String resourceFileName, String publicUrl) {
+               Objects.requireNonNull(namespace);
+               this.defaultPrefix = defaultPrefix;
+               Objects.requireNonNull(namespace);
+               this.namespace = namespace;
+               if (resourceFileName != null) {
+                       resource = getClass().getResource(RESOURCE_BASE + resourceFileName);
+                       Objects.requireNonNull(resource);
+               }
+               if (publicUrl != null)
+                       try {
+                               this.publicUrl = new URL(publicUrl);
+                       } catch (MalformedURLException e) {
+                               throw new IllegalArgumentException("Cannot interpret public URL", e);
+                       }
+       }
+
+       @Override
+       public String getDefaultPrefix() {
+               return defaultPrefix;
+       }
+
+       @Override
+       public String getNamespaceURI() {
+               return namespace;
+       }
+
+       @Override
+       public URL getSchemaResource() {
+               return resource;
+       }
+
+       public URL getPublicUrl() {
+               return publicUrl;
+       }
+
+}
index 474e07232d68d2bdae08eb3e456672b4010a2aad..3b47c1630aa4f63a41a30d0909d2ace7b13350de 100644 (file)
@@ -15,9 +15,9 @@ import org.argeo.api.cms.CmsSession;
 import org.argeo.api.cms.CmsState;
 import org.argeo.api.cms.DataAdminPrincipal;
 import org.argeo.api.uuid.UuidFactory;
-import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
-import org.argeo.util.CurrentSubject;
+import org.argeo.cms.util.CurrentSubject;
 
 /**
  * Multi-session {@link ProvidedRepository}, integrated with a CMS.
index 34d683605ac4e81240be687a04e4371f7e325d79..17a03fdc501bf9d138998f597c4e1663f0c330f5 100644 (file)
@@ -12,7 +12,6 @@ import javax.security.auth.Subject;
 
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentSession;
-import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.DName;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
@@ -119,23 +118,8 @@ class CmsContentSession implements ProvidedSession {
        }
 
        /*
-        * NAMESPACE CONTEXT
+        * EDITION
         */
-
-//     @Override
-//     public String getNamespaceURI(String prefix) {
-//             return RuntimeNamespaceContext.getNamespaceContext().getNamespaceURI(prefix);
-////           return NamespaceUtils.getNamespaceURI((p) -> contentRepository.getTypesManager().getPrefixes().get(p), prefix);
-//     }
-//
-//     @Override
-//     public Iterator<String> getPrefixes(String namespaceURI) {
-//             return RuntimeNamespaceContext.getNamespaceContext().getPrefixes(namespaceURI);
-////           return NamespaceUtils.getPrefixes((ns) -> contentRepository.getTypesManager().getPrefixes().entrySet().stream()
-////                           .filter(e -> e.getValue().equals(ns)).map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet()),
-////                           namespaceURI);
-//     }
-
        @Override
        public CompletionStage<ContentSession> edit(Consumer<ContentSession> work) {
                edition = CompletableFuture.supplyAsync(() -> {
@@ -172,7 +156,7 @@ class CmsContentSession implements ProvidedSession {
                return uuid;
        }
 
-       @Override
+//     @Override
        public Content getSessionRunDir() {
                if (sessionRunDir == null) {
                        String runDirPath = CmsContentRepository.RUN_BASE + '/' + uuid.toString();
@@ -181,30 +165,9 @@ class CmsContentSession implements ProvidedSession {
                        else {
                                Content runDir = get(CmsContentRepository.RUN_BASE);
                                // TODO deal with no run dir available?
-                               sessionRunDir = runDir.add(uuid.toString(),DName.collection.qName());
+                               sessionRunDir = runDir.add(uuid.toString(), DName.collection.qName());
                        }
                }
                return sessionRunDir;
        }
-
-//             @Override
-//             public String findNamespace(String prefix) {
-//                     return prefixes.get(prefix);
-//             }
-//
-//             @Override
-//             public Set<String> findPrefixes(String namespaceURI) {
-//                     Set<String> res = prefixes.entrySet().stream().filter(e -> e.getValue().equals(namespaceURI))
-//                                     .map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet());
-//
-//                     return res;
-//             }
-//
-//             @Override
-//             public String findPrefix(String namespaceURI) {
-//                     if (CrName.CR_NAMESPACE_URI.equals(namespaceURI) && prefixes.containsKey(CrName.CR_DEFAULT_PREFIX))
-//                             return CrName.CR_DEFAULT_PREFIX;
-//                     return ProvidedSession.super.findPrefix(namespaceURI);
-//             }
-
 }
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentTypes.java b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentTypes.java
deleted file mode 100644 (file)
index fff40c1..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-package org.argeo.cms.acr;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Objects;
-
-import org.argeo.api.acr.CrName;
-
-public enum CmsContentTypes {
-       //
-       // ARGEO
-       //
-       CR_2(CrName.CR_DEFAULT_PREFIX, CrName.CR_NAMESPACE_URI, "cr.xsd", null),
-       //
-       SLC("slc", "http://www.argeo.org/ns/slc", null, null),
-       //
-       ARGEO_LEGACY("argeo", "http://www.argeo.org/ns/argeo", null, null),
-       //
-       // EXTERNAL
-       //
-       XSD_2001("xs", "http://www.w3.org/2001/XMLSchema", "XMLSchema.xsd", "http://www.w3.org/2001/XMLSchema.xsd"),
-       //
-       XML_1998("xml", "http://www.w3.org/XML/1998/namespace", "xml.xsd", "http://www.w3.org/2001/xml.xsd"),
-       //
-       XLINK_1999("xlink", "http://www.w3.org/1999/xlink", "xlink.xsd", "http://www.w3.org/XML/2008/06/xlink.xsd"),
-       //
-       WEBDAV("D", "DAV:", null, "https://raw.githubusercontent.com/lookfirst/sardine/master/webdav.xsd"),
-       //
-       XSLT_2_0("xsl", "http://www.w3.org/1999/XSL/Transform", "schema-for-xslt20.xsd",
-                       "https://www.w3.org/2007/schema-for-xslt20.xsd"),
-       //
-       SVG_1_1("svg", "http://www.w3.org/2000/svg", "SVG.xsd",
-                       "https://raw.githubusercontent.com/oreillymedia/HTMLBook/master/schema/svg/SVG.xsd"),
-       //
-       DOCBOOK_5_0_1("dbk", "http://docbook.org/ns/docbook", "docbook.xsd",
-                       "http://docbook.org/xml/5.0.1/xsd/docbook.xsd"),
-       //
-       XML_EVENTS_2001("ev", "http://www.w3.org/2001/xml-events", "xml-events-attribs-1.xsd",
-                       "http://www.w3.org/MarkUp/SCHEMA/xml-events-attribs-1.xsd"),
-       //
-       XFORMS_2002("xforms", "http://www.w3.org/2002/xforms", "XForms-11-Schema.xsd",
-                       "https://www.w3.org/MarkUp/Forms/2007/XForms-11-Schema.xsd"),
-       //
-       DSML_v2("dsml", "urn:oasis:names:tc:DSML:2:0:core", "DSMLv2.xsd",
-                       "https://www.oasis-open.org/committees/dsml/docs/DSMLv2.xsd"),
-       //
-       // JCR (to be moved elsewhere)
-       //
-       JCR("jcr", "http://www.jcp.org/jcr/1.0", null,
-                       "https://jackrabbit.apache.org/archive/wiki/JCR/NamespaceRegistry_115513459.html"),
-       //
-       JCR_MIX("mix", "http://www.jcp.org/jcr/mix/1.0", null,
-                       "https://jackrabbit.apache.org/archive/wiki/JCR/NamespaceRegistry_115513459.html"),
-       //
-       JCR_NT("nt", "http://www.jcp.org/jcr/nt/1.0", null,
-                       "https://jackrabbit.apache.org/archive/wiki/JCR/NamespaceRegistry_115513459.html"),
-       //
-       JACKRABBIT("rep", "internal", null,
-                       "https://jackrabbit.apache.org/archive/wiki/JCR/NamespaceRegistry_115513459.html"),
-       //
-       JCRX("jcrx", "http://www.argeo.org/ns/jcrx", null, null),
-       //
-       ;
-
-       private final static String RESOURCE_BASE = "/org/argeo/cms/acr/schemas/";
-
-       private String defaultPrefix;
-       private String namespace;
-       private URL resource;
-       private URL publicUrl;
-
-       CmsContentTypes(String defaultPrefix, String namespace, String resourceFileName, String publicUrl) {
-               Objects.requireNonNull(namespace);
-               this.defaultPrefix = defaultPrefix;
-               Objects.requireNonNull(namespace);
-               this.namespace = namespace;
-               if (resourceFileName != null) {
-                       resource = getClass().getResource(RESOURCE_BASE + resourceFileName);
-                       Objects.requireNonNull(resource);
-               }
-               if (publicUrl != null)
-                       try {
-                               this.publicUrl = new URL(publicUrl);
-                       } catch (MalformedURLException e) {
-                               throw new IllegalArgumentException("Cannot interpret public URL", e);
-                       }
-       }
-
-       public String getDefaultPrefix() {
-               return defaultPrefix;
-       }
-
-       public String getNamespace() {
-               return namespace;
-       }
-
-       public URL getResource() {
-               return resource;
-       }
-
-       public URL getPublicUrl() {
-               return publicUrl;
-       }
-
-}
index 74e93fc0affa701c78233641e985d4e14f36a2cf..d324ac475283530ae658498f0bce39f305897225 100644 (file)
@@ -15,11 +15,11 @@ import org.argeo.api.acr.ContentRepository;
 import org.argeo.api.acr.ContentSession;
 import org.argeo.api.acr.DName;
 import org.argeo.api.cms.CmsAuth;
-import org.argeo.cms.CmsUserManager;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.argeo.util.CurrentSubject;
-import org.argeo.util.directory.Directory;
-import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.CmsDirectory;
+import org.argeo.api.cms.directory.CmsUserManager;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.UserDirectory;
+import org.argeo.cms.util.CurrentSubject;
 import org.osgi.service.useradmin.Role;
 
 /** Utilities and routines around {@link Content}. */
@@ -135,7 +135,7 @@ public class ContentUtils {
        }
 
        public static Content hierarchyUnitToContent(ContentSession contentSession, HierarchyUnit hierarchyUnit) {
-               Directory directory = hierarchyUnit.getDirectory();
+               CmsDirectory directory = hierarchyUnit.getDirectory();
                StringJoiner relativePath = new StringJoiner(SLASH_STRING);
                buildHierarchyUnitPath(hierarchyUnit, relativePath);
                String path = directoryPath(directory) + relativePath.toString();
@@ -143,8 +143,8 @@ public class ContentUtils {
                return content;
        }
 
-       /** The path to this {@link Directory}. Ends with a /. */
-       private static String directoryPath(Directory directory) {
+       /** The path to this {@link CmsDirectory}. Ends with a /. */
+       private static String directoryPath(CmsDirectory directory) {
                return CmsContentRepository.DIRECTORY_BASE + SLASH + directory.getName() + SLASH;
        }
 
index 5e7c191e269c5f3fef0ff401db2af253fee6149c..b9b940f051ac56fbeeb9166cd03f6a851cc0f4b8 100644 (file)
@@ -10,11 +10,11 @@ import javax.security.auth.Subject;
 import javax.security.auth.x500.X500Principal;
 
 import org.argeo.api.acr.ContentSession;
+import org.argeo.api.acr.ldap.LdapAttr;
 import org.argeo.api.acr.spi.ProvidedRepository;
 import org.argeo.api.uuid.MacAddressUuidFactory;
 import org.argeo.api.uuid.UuidFactory;
 import org.argeo.cms.acr.fs.FsContentProvider;
-import org.argeo.util.naming.LdapAttrs;
 
 /**
  * A standalone {@link ProvidedRepository} with a single {@link Subject} (which
@@ -86,7 +86,7 @@ public class SingleUserContentRepository extends AbstractContentRepository {
        public static void main(String... args) {
                Path homePath = Paths.get(System.getProperty("user.home"));
                String username = System.getProperty("user.name");
-               X500Principal principal = new X500Principal(LdapAttrs.uid + "=" + username + ",dc=localhost");
+               X500Principal principal = new X500Principal(LdapAttr.uid + "=" + username + ",dc=localhost");
                Subject subject = new Subject();
                subject.getPrincipals().add(principal);
 
index 0d38387326116f1fdc7f509a5b9b1220dc8f53af..61d8e04298971802987b1a1a1f99f0e50ba57d82 100644 (file)
@@ -20,12 +20,12 @@ public enum SvgAttrs implements QNamed {
 
        @Override
        public String getNamespace() {
-               return CmsContentTypes.SVG_1_1.getNamespace();
+               return CmsContentNamespace.SVG.getNamespaceURI();
        }
 
        @Override
        public String getDefaultPrefix() {
-               return CmsContentTypes.SVG_1_1.getDefaultPrefix();
+               return CmsContentNamespace.SVG.getDefaultPrefix();
        }
 
 }
index d3617e128729dd3678b09058e9cd12027ae9d299..c3bea5b60fae239c550179641d004f383730c2c6 100644 (file)
@@ -1,6 +1,7 @@
 package org.argeo.cms.acr;
 
 import java.io.IOException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -43,6 +44,7 @@ import org.apache.xerces.xs.XSTypeDefinition;
 import org.argeo.api.acr.CrAttributeType;
 import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.api.acr.RuntimeNamespaceContext;
+import org.argeo.api.acr.spi.ContentNamespace;
 import org.argeo.api.cms.CmsLog;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.SAXException;
@@ -57,7 +59,7 @@ class TypesManager {
        private SchemaFactory schemaFactory;
 
        /** Schema sources. */
-       private List<Source> sources = new ArrayList<>();
+       private List<URL> sources = new ArrayList<>();
 
        // cached
        private Schema schema;
@@ -65,7 +67,8 @@ class TypesManager {
        private XSModel xsModel;
        private SortedMap<QName, Map<QName, CrAttributeType>> types;
 
-       private boolean validating = true;
+       private boolean validating = false;
+       private boolean creatingXsModel = false;
 
        private final static boolean limited = false;
 
@@ -78,29 +81,24 @@ class TypesManager {
        }
 
        public void init() {
-               for (CmsContentTypes cs : CmsContentTypes.values()) {
-                       if (cs.getResource() != null) {
-                               StreamSource source = new StreamSource(cs.getResource().toExternalForm());
-                               sources.add(source);
-                       }
-                       RuntimeNamespaceContext.register(cs.getNamespace(), cs.getDefaultPrefix());
-               }
-
-               reload();
+               registerTypes(CmsContentNamespace.values());
        }
 
-       public void registerTypes(String defaultPrefix, String namespace, String xsdSystemId) {
+       public void registerTypes(ContentNamespace... namespaces) {
 //             if (prefixes.containsKey(defaultPrefix))
 //                     throw new IllegalStateException(
 //                                     "Prefix " + defaultPrefix + " is already mapped with " + prefixes.get(defaultPrefix));
 //             prefixes.put(defaultPrefix, namespace);
-               RuntimeNamespaceContext.register(namespace, defaultPrefix);
+               for (ContentNamespace contentNamespace : namespaces) {
+                       RuntimeNamespaceContext.register(contentNamespace.getNamespaceURI(), contentNamespace.getDefaultPrefix());
 
-               if (xsdSystemId != null) {
-                       sources.add(new StreamSource(xsdSystemId));
-                       reload();
-                       log.debug(() -> "Registered types " + namespace + " from " + xsdSystemId);
+                       if (contentNamespace.getSchemaResource() != null) {
+                               sources.add(contentNamespace.getSchemaResource());
+                               log.debug(() -> "Registered types " + contentNamespace.getNamespaceURI() + " from "
+                                               + contentNamespace.getSchemaResource().toExternalForm());
+                       }
                }
+               reload();
        }
 
        public Set<QName> listTypes() {
@@ -116,7 +114,21 @@ class TypesManager {
        private synchronized void reload() {
                try {
                        // schema
-                       schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()]));
+                       if (validating) {
+                               List<StreamSource> sourcesToUse = new ArrayList<>();
+                               for (URL sourceUrl : sources) {
+                                       sourcesToUse.add(new StreamSource(sourceUrl.toExternalForm()));
+                               }
+                               schema = schemaFactory.newSchema(sourcesToUse.toArray(new Source[sourcesToUse.size()]));
+//                             for (StreamSource source : sourcesToUse) {
+//                                     try {
+//                                             source.getInputStream().close();
+//                                     } catch (IOException e) {
+//                                             // TODO Auto-generated catch block
+//                                             e.printStackTrace();
+//                                     }
+//                             }
+                       }
 
                        // document builder factory
                        // we force usage of Xerces for predictability
@@ -124,31 +136,37 @@ class TypesManager {
                        documentBuilderFactory.setNamespaceAware(true);
                        if (!limited) {
                                documentBuilderFactory.setXIncludeAware(true);
-                               documentBuilderFactory.setSchema(getSchema());
-                               documentBuilderFactory.setValidating(validating);
+                               if (validating) {
+                                       documentBuilderFactory.setSchema(getSchema());
+                                       documentBuilderFactory.setValidating(validating);
+                               }
                        }
 
-                       // XS model
-                       // TODO use JVM implementation?
+                       if (creatingXsModel) {
+                               // XS model
+                               // TODO use JVM implementation?
 //                     DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
 //                     XSImplementation implementation = (XSImplementation) registry.getDOMImplementation("XS-Loader");
-                       XSImplementation xsImplementation = new XSImplementationImpl();
-                       XSLoader xsLoader = xsImplementation.createXSLoader(null);
-                       List<String> systemIds = new ArrayList<>();
-                       for (Source source : sources) {
-                               systemIds.add(source.getSystemId());
-                       }
-                       StringList sl = new StringListImpl(systemIds.toArray(new String[systemIds.size()]), systemIds.size());
-                       xsModel = xsLoader.loadURIList(sl);
+                               XSImplementation xsImplementation = new XSImplementationImpl();
+                               XSLoader xsLoader = xsImplementation.createXSLoader(null);
+                               List<String> systemIds = new ArrayList<>();
+                               for (URL sourceUrl : sources) {
+                                       systemIds.add(sourceUrl.toExternalForm());
+                               }
+                               StringList sl = new StringListImpl(systemIds.toArray(new String[systemIds.size()]), systemIds.size());
+                               xsModel = xsLoader.loadURIList(sl);
 
-                       // types
+                               // types
 //                     XSNamedMap map = xsModel.getComponents(XSConstants.ELEMENT_DECLARATION);
 //                     for (int i = 0; i < map.getLength(); i++) {
 //                             XSElementDeclaration eDec = (XSElementDeclaration) map.item(i);
 //                             QName type = new QName(eDec.getNamespace(), eDec.getName());
 //                             types.add(type);
 //                     }
-                       collectTypes();
+                               collectTypes();
+                               
+                               log.debug("Created XS model");
+                       }
                } catch (XSException | SAXException e) {
                        throw new IllegalStateException("Cannot reload types", e);
                }
@@ -412,34 +430,35 @@ class TypesManager {
        }
 
        public void printTypes() {
-               try {
-
-                       // Convert top level complex type definitions to node types
-                       log.debug("\n## TYPES");
-                       XSNamedMap map = xsModel.getComponents(XSConstants.TYPE_DEFINITION);
-                       for (int i = 0; i < map.getLength(); i++) {
-                               XSTypeDefinition tDef = (XSTypeDefinition) map.item(i);
-                               log.debug(tDef);
-                       }
-                       // Convert local (anonymous) complex type defs found in top level
-                       // element declarations
-                       log.debug("\n## ELEMENTS");
-                       map = xsModel.getComponents(XSConstants.ELEMENT_DECLARATION);
-                       for (int i = 0; i < map.getLength(); i++) {
-                               XSElementDeclaration eDec = (XSElementDeclaration) map.item(i);
-                               XSTypeDefinition tDef = eDec.getTypeDefinition();
-                               log.debug(eDec + ", " + tDef);
-                       }
-                       log.debug("\n## ATTRIBUTES");
-                       map = xsModel.getComponents(XSConstants.ATTRIBUTE_DECLARATION);
-                       for (int i = 0; i < map.getLength(); i++) {
-                               XSAttributeDeclaration eDec = (XSAttributeDeclaration) map.item(i);
-                               XSTypeDefinition tDef = eDec.getTypeDefinition();
-                               log.debug(eDec.getNamespace() + ":" + eDec.getName() + ", " + tDef);
+               if (xsModel != null)
+                       try {
+
+                               // Convert top level complex type definitions to node types
+                               log.debug("\n## TYPES");
+                               XSNamedMap map = xsModel.getComponents(XSConstants.TYPE_DEFINITION);
+                               for (int i = 0; i < map.getLength(); i++) {
+                                       XSTypeDefinition tDef = (XSTypeDefinition) map.item(i);
+                                       log.debug(tDef);
+                               }
+                               // Convert local (anonymous) complex type defs found in top level
+                               // element declarations
+                               log.debug("\n## ELEMENTS");
+                               map = xsModel.getComponents(XSConstants.ELEMENT_DECLARATION);
+                               for (int i = 0; i < map.getLength(); i++) {
+                                       XSElementDeclaration eDec = (XSElementDeclaration) map.item(i);
+                                       XSTypeDefinition tDef = eDec.getTypeDefinition();
+                                       log.debug(eDec + ", " + tDef);
+                               }
+                               log.debug("\n## ATTRIBUTES");
+                               map = xsModel.getComponents(XSConstants.ATTRIBUTE_DECLARATION);
+                               for (int i = 0; i < map.getLength(); i++) {
+                                       XSAttributeDeclaration eDec = (XSAttributeDeclaration) map.item(i);
+                                       XSTypeDefinition tDef = eDec.getTypeDefinition();
+                                       log.debug(eDec.getNamespace() + ":" + eDec.getName() + ", " + tDef);
+                               }
+                       } catch (ClassCastException | XSException e) {
+                               throw new RuntimeException(e);
                        }
-               } catch (ClassCastException | XSException e) {
-                       throw new RuntimeException(e);
-               }
 
        }
 
@@ -462,9 +481,9 @@ class TypesManager {
 //             return prefixes;
 //     }
 
-       public List<Source> getSources() {
-               return sources;
-       }
+//     public List<Source> getSources() {
+//             return sources;
+//     }
 
        public Schema getSchema() {
                return schema;
index 1313704f0feb890bad47985067a455028eb7e948..96e6eeaf3836c57887a6acb3c70802d2cf3a1909 100644 (file)
@@ -17,7 +17,7 @@ import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.cms.acr.AbstractContent;
 import org.argeo.cms.acr.ContentUtils;
 import org.argeo.cms.dav.DavResponse;
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.http.HttpStatus;
 
 public class DavContent extends AbstractContent {
        private final DavContentProvider provider;
index bc4bbfed3136c973c3700e28ad5f54e38c9d5422..374fcebbcdb21bda60c140e21a9b08c639f83864 100644 (file)
@@ -10,7 +10,7 @@ import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.cms.dav.DavClient;
 import org.argeo.cms.dav.DavResponse;
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.http.HttpStatus;
 
 public class DavContentProvider implements ContentProvider {
        private String mountPath;
index 2d337c0dda38d78bdfc5d78a428a6ae110942cd8..b737b50a1ea48ca63bb1eddcfd544d6c55d5778e 100644 (file)
@@ -10,15 +10,15 @@ import java.util.TreeSet;
 
 import javax.xml.namespace.QName;
 
+import org.argeo.api.acr.ArgeoNamespace;
 import org.argeo.api.acr.ContentName;
 import org.argeo.api.acr.CrAttributeType;
-import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.acr.ldap.LdapObj;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.cms.acr.AbstractContent;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
 
 abstract class AbstractDirectoryContent extends AbstractContent {
        protected final DirectoryContentProvider provider;
@@ -50,11 +50,11 @@ abstract class AbstractDirectoryContent extends AbstractContent {
                Set<QName> keys = new TreeSet<>(NamespaceUtils.QNAME_COMPARATOR);
                keys: for (Enumeration<String> it = properties.keys(); it.hasMoreElements();) {
                        String key = it.nextElement();
-                       if (key.equalsIgnoreCase(LdapAttrs.objectClass.name()))
+                       if (key.equalsIgnoreCase(LdapAttr.objectClass.name()))
                                continue keys;
-                       if (key.equalsIgnoreCase(LdapAttrs.objectClasses.name()))
+                       if (key.equalsIgnoreCase(LdapAttr.objectClasses.name()))
                                continue keys;
-                       ContentName name = new ContentName(CrName.LDAP_NAMESPACE_URI, key, provider);
+                       ContentName name = new ContentName(ArgeoNamespace.LDAP_NAMESPACE_URI, key, provider);
                        keys.add(name);
                }
                return keys;
@@ -64,16 +64,16 @@ abstract class AbstractDirectoryContent extends AbstractContent {
        public List<QName> getContentClasses() {
                Dictionary<String, Object> properties = doGetProperties();
                List<QName> contentClasses = new ArrayList<>();
-               String objectClass = properties.get(LdapAttrs.objectClass.name()).toString();
-               contentClasses.add(new ContentName(CrName.LDAP_NAMESPACE_URI, objectClass, provider));
+               String objectClass = properties.get(LdapAttr.objectClass.name()).toString();
+               contentClasses.add(new ContentName(ArgeoNamespace.LDAP_NAMESPACE_URI, objectClass, provider));
 
-               String[] objectClasses = properties.get(LdapAttrs.objectClasses.name()).toString().split("\\n");
+               String[] objectClasses = properties.get(LdapAttr.objectClasses.name()).toString().split("\\n");
                objectClasses: for (String oc : objectClasses) {
-                       if (LdapObjs.top.name().equalsIgnoreCase(oc))
+                       if (LdapObj.top.name().equalsIgnoreCase(oc))
                                continue objectClasses;
                        if (objectClass.equalsIgnoreCase(oc))
                                continue objectClasses;
-                       contentClasses.add(new ContentName(CrName.LDAP_NAMESPACE_URI, oc, provider));
+                       contentClasses.add(new ContentName(ArgeoNamespace.LDAP_NAMESPACE_URI, oc, provider));
                }
                return contentClasses;
        }
@@ -81,8 +81,7 @@ abstract class AbstractDirectoryContent extends AbstractContent {
        @Override
        public Object put(QName key, Object value) {
                Object previous = get(key);
-               // TODO deal with typing
-               doGetProperties().put(key.getLocalPart(), value);
+               provider.getUserManager().edit(() -> doGetProperties().put(key.getLocalPart(), value));
                return previous;
        }
 
index 4e738ae2b8399e315d68a45816373191e34725b9..6e39280cee86a12bbb4d1dfa85f51ddedb8c392a 100644 (file)
@@ -10,13 +10,13 @@ import javax.xml.namespace.QName;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentName;
 import org.argeo.api.acr.spi.ProvidedSession;
-import org.argeo.util.directory.Directory;
-import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.CmsDirectory;
+import org.argeo.api.cms.directory.HierarchyUnit;
 
 class DirectoryContent extends AbstractDirectoryContent {
-       private Directory directory;
+       private CmsDirectory directory;
 
-       public DirectoryContent(ProvidedSession session, DirectoryContentProvider provider, Directory directory) {
+       public DirectoryContent(ProvidedSession session, DirectoryContentProvider provider, CmsDirectory directory) {
                super(session, provider);
                this.directory = directory;
        }
@@ -45,4 +45,14 @@ class DirectoryContent extends AbstractDirectoryContent {
                return provider.getRootContent(getSession());
        }
 
+       @SuppressWarnings("unchecked")
+       @Override
+       public <A> A adapt(Class<A> clss) {
+               if (clss.equals(HierarchyUnit.class))
+                       return (A) directory;
+               if (clss.equals(CmsDirectory.class))
+                       return (A) directory;
+               return super.adapt(clss);
+       }
+
 }
index aab5d6dc06a56ab69cdd533a800450c38f01c8a9..8b6eb6bbd4b2d8e73413dfa5aaae82383f44a472 100644 (file)
@@ -7,18 +7,18 @@ import java.util.List;
 
 import javax.xml.namespace.QName;
 
+import org.argeo.api.acr.ArgeoNamespace;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentName;
 import org.argeo.api.acr.ContentNotFoundException;
-import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedSession;
-import org.argeo.cms.CmsUserManager;
+import org.argeo.api.cms.directory.CmsUserManager;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.UserDirectory;
 import org.argeo.cms.acr.AbstractContent;
 import org.argeo.cms.acr.ContentUtils;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.argeo.util.directory.HierarchyUnit;
 import org.osgi.service.useradmin.User;
 
 public class DirectoryContentProvider implements ContentProvider {
@@ -92,22 +92,26 @@ public class DirectoryContentProvider implements ContentProvider {
 
        @Override
        public String getNamespaceURI(String prefix) {
-               if (CrName.LDAP_DEFAULT_PREFIX.equals(prefix))
-                       return CrName.LDAP_NAMESPACE_URI;
-               throw new IllegalArgumentException("Only prefix " + CrName.LDAP_DEFAULT_PREFIX + " is supported");
+               if (ArgeoNamespace.LDAP_DEFAULT_PREFIX.equals(prefix))
+                       return ArgeoNamespace.LDAP_NAMESPACE_URI;
+               throw new IllegalArgumentException("Only prefix " + ArgeoNamespace.LDAP_DEFAULT_PREFIX + " is supported");
        }
 
        @Override
        public Iterator<String> getPrefixes(String namespaceURI) {
-               if (CrName.LDAP_NAMESPACE_URI.equals(namespaceURI))
-                       return Collections.singletonList(CrName.LDAP_DEFAULT_PREFIX).iterator();
-               throw new IllegalArgumentException("Only namespace URI " + CrName.LDAP_NAMESPACE_URI + " is supported");
+               if (ArgeoNamespace.LDAP_NAMESPACE_URI.equals(namespaceURI))
+                       return Collections.singletonList(ArgeoNamespace.LDAP_DEFAULT_PREFIX).iterator();
+               throw new IllegalArgumentException("Only namespace URI " + ArgeoNamespace.LDAP_NAMESPACE_URI + " is supported");
        }
 
        public void setUserManager(CmsUserManager userManager) {
                this.userManager = userManager;
        }
 
+       public CmsUserManager getUserManager() {
+               return userManager;
+       }
+
        UserManagerContent getRootContent(ProvidedSession session) {
                return new UserManagerContent(session);
        }
index 1e4aad77328a7805df4732e51935eafc71e5a047..5acf8ab63fc07711f1956ed4fa3380c952f294a5 100644 (file)
@@ -13,9 +13,9 @@ import org.argeo.api.acr.ContentName;
 import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.DName;
 import org.argeo.api.acr.spi.ProvidedSession;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.argeo.util.directory.Directory;
-import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.CmsDirectory;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.UserDirectory;
 import org.osgi.service.useradmin.Role;
 
 class HierarchyUnitContent extends AbstractDirectoryContent {
@@ -46,7 +46,7 @@ class HierarchyUnitContent extends AbstractDirectoryContent {
        @Override
        public Content getParent() {
                HierarchyUnit parentHu = hierarchyUnit.getParent();
-               if (parentHu instanceof Directory) {
+               if (parentHu instanceof CmsDirectory) {
                        return new DirectoryContent(getSession(), provider, hierarchyUnit.getDirectory());
                }
                return new HierarchyUnitContent(getSession(), provider, parentHu);
index 7aa144633689c5d668f1297aa4ad7be81db434ac..64feb1d6735955310ee458a00c50a53adbe842c8 100644 (file)
@@ -7,10 +7,8 @@ import javax.xml.namespace.QName;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentName;
 import org.argeo.api.acr.spi.ProvidedSession;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.osgi.service.useradmin.Group;
+import org.argeo.api.cms.directory.UserDirectory;
 import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
 
 class RoleContent extends AbstractDirectoryContent {
 
@@ -43,11 +41,7 @@ class RoleContent extends AbstractDirectoryContent {
        @SuppressWarnings("unchecked")
        @Override
        public <A> A adapt(Class<A> clss) {
-               if (clss.equals(Group.class))
-                       return (A) role;
-               else if (clss.equals(User.class))
-                       return (A) role;
-               else if (clss.equals(Role.class))
+               if (Role.class.isAssignableFrom(clss))
                        return (A) role;
                return super.adapt(clss);
        }
index 2d30cedec3b8f936ae395e175fd8ec539d4cd7c2..43cae85721bf6b96c3f577f157f64b56845c11b2 100644 (file)
@@ -44,7 +44,7 @@ import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.cms.acr.AbstractContent;
 import org.argeo.cms.acr.ContentUtils;
-import org.argeo.util.FsUtils;
+import org.argeo.cms.util.FsUtils;
 
 /** Content persisted as a filesystem {@link Path}. */
 public class FsContent extends AbstractContent implements ProvidedContent {
index 59a4d8deb5616f12c6b1b24c61406726f3f121b2..9b1b9668303f066e2106de3aa4a296edcabbf55d 100644 (file)
@@ -13,8 +13,8 @@ import java.util.Objects;
 import java.util.TreeMap;
 import java.util.stream.Collectors;
 
+import org.argeo.api.acr.ArgeoNamespace;
 import org.argeo.api.acr.ContentResourceException;
-import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.api.acr.RuntimeNamespaceContext;
 import org.argeo.api.acr.spi.ContentProvider;
@@ -62,10 +62,10 @@ public class FsContentProvider implements ContentProvider {
                        }
 
                        // defaults
-                       addDefaultNamespace(udfav, CrName.CR_DEFAULT_PREFIX, CrName.CR_NAMESPACE_URI);
-                       addDefaultNamespace(udfav, "basic", CrName.CR_NAMESPACE_URI);
-                       addDefaultNamespace(udfav, "owner", CrName.CR_NAMESPACE_URI);
-                       addDefaultNamespace(udfav, "posix", CrName.CR_NAMESPACE_URI);
+                       addDefaultNamespace(udfav, ArgeoNamespace.CR_DEFAULT_PREFIX, ArgeoNamespace.CR_NAMESPACE_URI);
+                       addDefaultNamespace(udfav, "basic", ArgeoNamespace.CR_NAMESPACE_URI);
+                       addDefaultNamespace(udfav, "owner", ArgeoNamespace.CR_NAMESPACE_URI);
+                       addDefaultNamespace(udfav, "posix", ArgeoNamespace.CR_NAMESPACE_URI);
                } catch (IOException e) {
                        throw new RuntimeException("Cannot read namespaces from " + rootPath, e);
                }
diff --git a/org.argeo.cms/src/org/argeo/cms/acr/schemas/XForms-11-Schema.xsd b/org.argeo.cms/src/org/argeo/cms/acr/schemas/XForms-11-Schema.xsd
deleted file mode 100644 (file)
index 881bfcb..0000000
+++ /dev/null
@@ -1,1571 +0,0 @@
-<?xml version="1.0"?>
-<xsd:schema targetNamespace="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" elementFormDefault="qualified">
-       <!--
-  Changes:
-26-Aug MJD fixed typo where more than one child allowed on <instance>
-04-Sep MJD fixed typo on <send> : attribute 'submission' is required
-04-Sep MJD fixed typo on <rebuild><recalculate><revalidate><refresh>: '' attribute is required
-06-Sep MJD clarified specific allowed values of @level on <message>
-06-Sep MJD removed UI Common attributes from <help><hint><alert><label>
-09-Sep MJD changed minOccurrs and maxOccurs to use XPath expressions, default values
-09-Sep MJD fixed typo: added linking attributes to <message>
-09-Sep MJD removed <extension> from content models of <mode> and UI common elements
-09-Sep MJD fixed typo: removed 'format' attribute
-17-Sep MJD fixed typo: <output> now uses the attribute group for binding attributes, instead of similarly named individual attrs
-17-Sep MJD added XPathExpression simpleType for internal use. This doesn't actually change anything, but makes
-the Schema a better documentation resource (instead of using xsd:string for everything)
-17-Sep MJD removed 'mediatype' attribute from <submission>, as it was unused
-17-Sep MJD fixed typo: only 'ref' and 'bind' attributes, not 'model' on <submission>
-17-Sep MJD added XML Events attributes to <model>
-17-Sep MJD in accordance with 3.2.1, removed all id attributes
-19-Sep MJD fixed typo: clarified that nested <action>s are permitted.
-19-Sep MJD factor UI.Inline into <group>. Renamed <group>s and <attributeGroup>s to match the prose names
-19-Sep MJD changed to agreed-upon namespace for CR
-25-Sep MJD fixed typo: added UI.Inlne to content model of <message>, enabled mixed content
-29-Sep MJD fixed typo: 'model' required on <reset>
-29-Sep MJD fixed typo: binding attributes allowed on <submit>
-29-Sep MJD fixed typo: explicit enumerated values for 'show' on <load>
-04-Oct MJD 'resource' attribute not required
-
-12-Nov 2002 : Published as CR
-
-13-Jan MJD added new attribute includenamespaceprefixes on <submission>
-13-Jan MJD added UI Common elements to content model of <group>
-03-Feb MJD synchoninzed duration types with 15 Nov Query Operators document
-31-Mar MJD added mediatype attribute on <submission>
-14-May MJD typo : "xsd:NCName"
-26-Jun MJD removed 'accesskey' and 'navindex' (over to host language definition)
-
-01-Aug 2003 : Published as PR
-
-15-Sep MJD final namespace
-15-Sep MJD corrected content model of <value>
-15-Sep MJD changed the name of the import for XML Events to highlight that only the attributes are used
-
-1.0 Second Edition errata
-
-16-Apr 2005 RAM - erratum E4 - optional @model
-16-Apr 2005 RAM - erratum E22 - default value for @show
-16-Apr 2005 RAM - erratum E54 - remove xforms:minOccurs and xforms:maxOccurs
-26-Jun 2005 RAM - erratum E71 - allow an empty case element
-
-16-Jun 2006 JMB - erratum E69 - instance attribute in submission; id in common attributes
-
-15-Aug-2006 CFW - erratum E18 on 2nd ed. Added Action to content model for Case
-
-09-Sep 2006 JMB - non-substantive: explicitly declared some use="optional" settings, 
-                  substantive: erratum E18 on 2nd ed. Declared default false for selected attribute of case
-                  substantive: erratum E21 on 2nd ed. Added multipart-post to enumeration of method attribute
-23-Nov 2006 JMB - substantive: erratum E32 on 2nd ed. switch in repeat
-17-Jul 2007 JMB - substantive: erratum E41 on 2nd ed. version attribute and associated simple types
-
-XForms 1.1
-
-25 Oct 2007 CFW, NvdB and JMB - Updated to XForms 1.1
-21 Nov 2007 JMB: Fixed description of card-number datatype
-08 Apr 2008 JMB: Fixed NCName (was NCNAME)
-30 MAY 2008 JMB: Changed card-number to allow zero or more digits
-22 JUN 2008 JMB: Renamed UI.Inline to UI.Content
-07 SEP 2008 LLK: Added element header attribute combine. header now allows one name, multiple value.
-09 MAR 2009 JMB: Changed @separator default to ampersand
-19 MAY 2009 JMB: Added submission/@targetref, dispatch/@targetid and dispatch/targetid
-10 JUN 2009 JMB: Moved switch/case from global space to being local to switch for clarity
-13 JAN 2010 JMB: Put maxOccurs=1 on instance content to limit to one child element in an instance
-16 SEP 2010 JBM: Added xforms:duration datatype (1.1 Erratum #1), added UICommon before ListUICommon on select/select1 (1.1 Erratum #2)
--->
-       <xsd:import namespace="http://www.w3.org/2001/xml-events" schemaLocation="xml-events-attribs-1.xsd"/>
-       <xsd:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="XMLSchema.xsd"/>
-
-       <!--
-structural elements
--->
-       <xsd:attributeGroup name="Common.Attributes">
-               <xsd:annotation>
-                       <xsd:documentation>Attributes for _every_ element in XForms</xsd:documentation>
-               </xsd:annotation>
-               <xsd:attribute name="id" type="xsd:ID" use="optional"/>
-               <xsd:anyAttribute namespace="##other"/>
-       </xsd:attributeGroup>
-
-       <xsd:attributeGroup name="Single.Node.Binding.Attributes">
-               <xsd:attribute name="model" type="xsd:IDREF" use="optional"/>
-               <xsd:attribute name="ref" type="xforms:XPathExpression" use="optional"/>
-               <xsd:attribute name="bind" type="xsd:IDREF" use="optional"/>
-       </xsd:attributeGroup>
-
-       <xsd:attributeGroup name="Nodeset.Binding.Attributes">
-               <xsd:attribute name="model" type="xsd:IDREF" use="optional"/>
-               <xsd:attribute name="nodeset" type="xforms:XPathExpression" use="optional"/>
-               <xsd:attribute name="bind" type="xsd:IDREF" use="optional"/>
-       </xsd:attributeGroup>
-
-       <xsd:attributeGroup name="Linking.Attributes">
-               <xsd:attribute name="src" type="xsd:anyURI"/>
-       </xsd:attributeGroup>
-
-       <xsd:element name="model">
-               <xsd:complexType>
-                       <xsd:sequence minOccurs="0" maxOccurs="unbounded">
-                               <xsd:choice>
-                                       <xsd:element ref="xforms:instance"/>
-                                       <xsd:element ref="xsd:schema"/>
-                                       <xsd:element ref="xforms:submission"/>
-                                       <xsd:element ref="xforms:bind"/>
-                                       <xsd:group ref="xforms:Action"/>
-                               </xsd:choice>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attribute name="functions" type="xforms:QNameList" use="optional"/>
-                       <xsd:attribute name="schema" type="xforms:anyURIList" use="optional"/>
-                       <xsd:attribute name="version" type="xforms:versionList" use="optional"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <xsd:element name="instance">
-               <xsd:annotation>
-                       <xsd:documentation>instance container.</xsd:documentation>
-               </xsd:annotation>
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="1"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Linking.Attributes"/>
-                       <xsd:attribute name="resource" type="xsd:anyURI" use="optional"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <xsd:element name="bind">
-               <xsd:annotation>
-                       <xsd:documentation>Definition of bind container.</xsd:documentation>
-               </xsd:annotation>
-               <xsd:complexType>
-                       <xsd:sequence minOccurs="0" maxOccurs="unbounded">
-                               <xsd:element ref="xforms:bind"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="nodeset" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="calculate" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="type" type="xsd:QName" use="optional"/>
-                       <xsd:attribute name="required" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="constraint" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="relevant" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="readonly" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="p3ptype" type="xsd:string" use="optional"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <xsd:element name="extension">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:any namespace="##other"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <!--
-User Interface form controls
--->
-       <xsd:group name="Core.Form.Controls">
-               <xsd:choice>
-                       <xsd:element ref="xforms:input"/>
-                       <xsd:element ref="xforms:secret"/>
-                       <xsd:element ref="xforms:textarea"/>
-                       <xsd:element ref="xforms:output"/>
-                       <xsd:element ref="xforms:upload"/>
-                       <xsd:element ref="xforms:select1"/>
-                       <xsd:element ref="xforms:select"/>
-                       <xsd:element ref="xforms:range"/>
-                       <xsd:element ref="xforms:submit"/>
-                       <xsd:element ref="xforms:trigger"/>
-               </xsd:choice>
-       </xsd:group>
-
-       <xsd:group name="Container.Form.Controls">
-               <xsd:choice>
-                       <xsd:element ref="xforms:group"/>
-                       <xsd:element ref="xforms:switch"/>
-                       <xsd:element ref="xforms:repeat"/>
-               </xsd:choice>
-       </xsd:group>
-
-       <xsd:attributeGroup name="UI.Common.Attrs">
-               <xsd:attribute name="appearance" type="xforms:appearanceType" use="optional"/>
-       </xsd:attributeGroup>
-
-       <xsd:group name="UI.Content">
-               <xsd:sequence>
-                       <xsd:choice minOccurs="0">
-                               <xsd:element ref="xforms:output"/>
-                               <!-- containing document language to add additional allowed content here -->
-                       </xsd:choice>
-               </xsd:sequence>
-       </xsd:group>
-
-       <xsd:group name="UI.Common">
-               <xsd:sequence>
-                       <xsd:choice minOccurs="0" maxOccurs="unbounded">
-                               <xsd:element ref="xforms:help"/>
-                               <xsd:element ref="xforms:hint"/>
-                               <xsd:element ref="xforms:alert"/>
-                               <xsd:group ref="xforms:Action"/>
-                       </xsd:choice>
-               </xsd:sequence>
-       </xsd:group>
-
-       <xsd:element name="label">
-               <xsd:complexType mixed="true">
-                       <xsd:group ref="xforms:UI.Content"/>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="hint">
-               <xsd:complexType mixed="true">
-                       <xsd:group ref="xforms:UI.Content"/>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="help">
-               <xsd:complexType mixed="true">
-                       <xsd:group ref="xforms:UI.Content"/>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="alert">
-               <xsd:complexType mixed="true">
-                       <xsd:group ref="xforms:UI.Content"/>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <xsd:group name="List.UI.Common">
-               <xsd:sequence>
-                       <xsd:choice>
-                               <xsd:element ref="xforms:item"/>
-                               <xsd:element ref="xforms:itemset"/>
-                               <xsd:element ref="xforms:choices"/>
-                       </xsd:choice>
-               </xsd:sequence>
-       </xsd:group>
-       <xsd:element name="item">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:element ref="xforms:value"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="itemset">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:choice>
-                                       <xsd:element ref="xforms:value"/>
-                                       <xsd:element ref="xforms:copy"/>
-                               </xsd:choice>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Nodeset.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="choices">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label" minOccurs="0"/>
-                               <xsd:sequence maxOccurs="unbounded">
-                                       <xsd:choice>
-                                               <xsd:element ref="xforms:choices"/>
-                                               <xsd:element ref="xforms:item"/>
-                                               <xsd:element ref="xforms:itemset"/>
-                                       </xsd:choice>
-                               </xsd:sequence>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <xsd:element name="value">
-               <xsd:complexType>
-                       <xsd:simpleContent>
-                               <xsd:extension base="xsd:string">
-                                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                                       <xsd:attribute name="value" type="xforms:XPathExpression" use="optional"/>
-                               </xsd:extension>
-                       </xsd:simpleContent>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="copy">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-<!--
-       <xsd:element name="filename">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="mediatype">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
--->
-       <xsd:complexType name="filename">
-               <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-               <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-       </xsd:complexType>
-       <xsd:complexType name="mediatype">
-               <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-               <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-       </xsd:complexType>
-       <xsd:complexType name="mediatypeWithValue">
-               <xsd:complexContent>
-                       <xsd:extension base="xforms:mediatype">
-                               <xsd:attribute name="value" type="xforms:XPathExpression" use="optional"/>
-                       </xsd:extension>
-               </xsd:complexContent>
-       </xsd:complexType>
-
-       <xsd:element name="input">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attribute name="inputmode" type="xsd:string" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="incremental" type="xsd:boolean" use="optional" default="false"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="secret">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attribute name="inputmode" type="xsd:string" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="incremental" type="xsd:boolean" use="optional" default="false"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="textarea">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attribute name="inputmode" type="xsd:string" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="incremental" type="xsd:boolean" use="optional" default="false"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="upload">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <!--
-                               <xsd:element ref="xforms:filename" minOccurs="0"/>
-                               <xsd:element ref="xforms:mediatype" minOccurs="0"/>
-                               -->
-                               <xsd:element name="filename" type="xforms:filename" minOccurs="0"/>
-                               <xsd:element name="mediatype" type="xforms:mediatype" minOccurs="0"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="mediatype" type="xsd:string" use="optional"/>
-                       <xsd:attribute name="incremental" type="xsd:boolean" use="optional" default="false"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="select1">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                               <xsd:group ref="xforms:List.UI.Common" maxOccurs="unbounded"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="selection" use="optional" default="closed">
-                               <xsd:simpleType>
-                                       <xsd:restriction base="xsd:string">
-                                               <xsd:enumeration value="open"/>
-                                               <xsd:enumeration value="closed"/>
-                                       </xsd:restriction>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-                       <xsd:attribute name="incremental" type="xsd:boolean" use="optional" default="true"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="select">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                               <xsd:group ref="xforms:List.UI.Common" maxOccurs="unbounded"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="selection" use="optional" default="closed">
-                               <xsd:simpleType>
-                                       <xsd:restriction base="xsd:string">
-                                               <xsd:enumeration value="open"/>
-                                               <xsd:enumeration value="closed"/>
-                                       </xsd:restriction>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-                       <xsd:attribute name="incremental" type="xsd:boolean" use="optional" default="true"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="range">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="start" type="xsd:string" use="optional"/>
-                       <xsd:attribute name="end" type="xsd:string" use="optional"/>
-                       <xsd:attribute name="step" type="xsd:string" use="optional"/>
-                       <xsd:attribute name="incremental" type="xsd:boolean" use="optional" default="false"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="trigger">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="output">
-               <xsd:complexType>
-                       <xsd:sequence minOccurs="0">
-                               <xsd:element ref="xforms:label"/>
-                               <!--
-                               <xsd:element ref="xforms:mediatype" minOccurs="0"/>
-                               -->
-                               <xsd:element name="mediatype" type="xforms:mediatypeWithValue" minOccurs="0"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attribute name="appearance" type="xforms:appearanceType" use="optional"/>
-                       <xsd:attribute name="value" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="mediatype" type="xsd:string" use="optional"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="submit">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label"/>
-                               <xsd:group ref="xforms:UI.Common" minOccurs="0" maxOccurs="unbounded"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="submission" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <!--
-Advanced User Interface
--->
-       <xsd:attribute name="repeat-nodeset" type="xforms:XPathExpression"/>
-       <xsd:attribute name="repeat-model" type="xsd:IDREF"/>
-       <xsd:attribute name="repeat-bind" type="xsd:IDREF"/>
-       <xsd:attribute name="repeat-startindex" type="xsd:positiveInteger"/>
-       <xsd:attribute name="repeat-number" type="xsd:nonNegativeInteger"/>
-       
-       <xsd:element name="repeat">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:sequence minOccurs="0" maxOccurs="unbounded">
-                                       <xsd:choice>
-                                               <xsd:group ref="xforms:Core.Form.Controls"/>
-                                               <xsd:group ref="xforms:Container.Form.Controls"/>
-                                               <xsd:group ref="xforms:Action"/>
-                                               <!-- containing document language to add additional allowed content here -->
-                                       </xsd:choice>
-                               </xsd:sequence>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Nodeset.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-                       <xsd:attribute name="startindex" type="xsd:positiveInteger"/>
-                       <xsd:attribute name="number" type="xsd:nonNegativeInteger"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="group">
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <xsd:element ref="xforms:label" minOccurs="0"/>
-                               <xsd:sequence minOccurs="0" maxOccurs="unbounded">
-                                       <xsd:choice>
-                                               <xsd:group ref="xforms:Core.Form.Controls"/>
-                                               <xsd:group ref="xforms:Container.Form.Controls"/>
-                                               <xsd:group ref="xforms:UI.Common"/>
-                                               <!-- containing document language to add additional allowed content here -->
-                                       </xsd:choice>
-                               </xsd:sequence>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="switch">
-               <xsd:complexType>
-                       <xsd:sequence maxOccurs="unbounded">
-                               <xsd:element name="case">
-                                       <xsd:complexType>
-                                               <xsd:sequence>
-                                                       <xsd:element ref="xforms:label" minOccurs="0"/>
-                                                       <xsd:sequence minOccurs="0" maxOccurs="unbounded">
-                                                               <xsd:choice>
-                                                                       <xsd:group ref="xforms:Core.Form.Controls"/>
-                                                                       <xsd:group ref="xforms:Container.Form.Controls"/>
-                                                                       <xsd:group ref="xforms:Action"/>
-                                                                       <!-- containing document language to add additional allowed content here -->
-                                                               </xsd:choice>
-                                                       </xsd:sequence>
-                                               </xsd:sequence>
-                                               <xsd:attribute name="selected" type="xsd:boolean" use="optional" default="false"/>
-                                               <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                                       </xsd:complexType>
-                               </xsd:element>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:UI.Common.Attrs"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <!--
-XForms Actions
--->
-
-       <xsd:attributeGroup name="XML.Events">
-               <xsd:attribute ref="ev:event"/>
-               <xsd:attribute ref="ev:observer"/>
-               <xsd:attribute ref="ev:target"/>
-               <xsd:attribute ref="ev:handler"/>
-               <xsd:attribute ref="ev:phase"/>
-               <xsd:attribute ref="ev:propagate"/>
-               <xsd:attribute ref="ev:defaultAction"/>
-       </xsd:attributeGroup>
-
-       <xsd:attributeGroup name="Common.Action.Attributes">
-               <xsd:annotation>
-                       <xsd:documentation>Attributes for _every_ action in XForms</xsd:documentation>
-               </xsd:annotation>
-               <xsd:attribute name="if" type="xforms:XPathExpression" use="optional"/>
-               <xsd:attribute name="while" type="xforms:XPathExpression" use="optional"/>
-       </xsd:attributeGroup>
-
-       <xsd:group name="Action">
-               <xsd:sequence>
-                       <xsd:choice minOccurs="0" maxOccurs="unbounded">
-                               <xsd:element ref="xforms:action"/>
-                               <xsd:element ref="xforms:setvalue"/>
-                               <xsd:element ref="xforms:insert"/>
-                               <xsd:element ref="xforms:delete"/>
-                               <xsd:element ref="xforms:setindex"/>
-                               <xsd:element ref="xforms:toggle"/>
-                               <xsd:element ref="xforms:setfocus"/>
-                               <xsd:element ref="xforms:dispatch"/>
-                               <xsd:element ref="xforms:rebuild"/>
-                               <xsd:element ref="xforms:recalculate"/>
-                               <xsd:element ref="xforms:revalidate"/>
-                               <xsd:element ref="xforms:refresh"/>
-                               <xsd:element ref="xforms:reset"/>
-                               <xsd:element ref="xforms:load"/>
-                               <xsd:element ref="xforms:send"/>
-                               <xsd:element ref="xforms:message"/>
-                       </xsd:choice>
-               </xsd:sequence>
-       </xsd:group>
-
-       <xsd:element name="action">
-               <xsd:complexType>
-                       <xsd:sequence maxOccurs="unbounded">
-                               <xsd:group ref="xforms:Action"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="setvalue">
-               <xsd:complexType>
-                       <xsd:simpleContent>
-                               <xsd:extension base="xsd:string">
-                                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                                       <xsd:attribute name="value" type="xforms:XPathExpression" use="optional"/>
-                                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-                               </xsd:extension>
-                       </xsd:simpleContent>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="insert">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Nodeset.Binding.Attributes"/>
-                       <xsd:attribute name="at" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="context" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="origin" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="position" use="optional">
-                               <xsd:simpleType>
-                                       <xsd:restriction base="xsd:string">
-                                               <xsd:enumeration value="before"/>
-                                               <xsd:enumeration value="after"/>
-                                       </xsd:restriction>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="delete">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Nodeset.Binding.Attributes"/>
-                       <xsd:attribute name="at" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="context" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="setindex">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="repeat" type="xsd:IDREF" use="required"/>
-                       <xsd:attribute name="index" type="xforms:XPathExpression" use="required"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="toggle">
-               <xsd:complexType>
-                       <xsd:sequence minOccurs="0" maxOccurs="1">
-                               <xsd:element name="case" type="xforms:ValueTemplate"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="case" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="setfocus">
-               <xsd:complexType>
-                       <xsd:sequence minOccurs="0" maxOccurs="1">
-                               <xsd:element name="control" type="xforms:ValueTemplate"/>
-                       </xsd:sequence>                 
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="control" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="dispatch">
-               <xsd:complexType>
-                       <!-- Need to be able to say only zero or one of each child, but order independent.
-                            This gets as close as possible with schema. -->
-                       <xsd:sequence minOccurs="0" maxOccurs="3">
-                           <xsd:choice>
-                               <xsd:element name="name" type="xforms:ValueTemplate"/>
-                               <xsd:element name="targetid" type="xforms:ValueTemplate"/>
-                               <xsd:element name="target" type="xforms:ValueTemplate"/>
-                               <xsd:element name="delay" type="xforms:ValueTemplate"/>
-                           </xsd:choice>
-                       </xsd:sequence>                         
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="name" type="xsd:NMTOKEN" use="optional"/>
-                       <xsd:attribute name="targetid" type="xsd:IDREF" use="optional"/>
-                       <xsd:attribute name="target" type="xsd:IDREF" use="optional"/>
-                       <xsd:attribute name="delay" type="xsd:string" use="optional" default=""/>
-                       <xsd:attribute name="bubbles" type="xsd:boolean" use="optional" default="true"/>
-                       <xsd:attribute name="cancelable" type="xsd:boolean" use="optional" default="true"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="rebuild">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="model" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="recalculate">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="model" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="revalidate">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="model" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="refresh">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="model" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="reset">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-                       <xsd:attribute name="model" type="xsd:IDREF" use="optional"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="load">
-               <xsd:complexType>
-                       <xsd:sequence minOccurs="0" maxOccurs="1">
-                               <xsd:element name="resource" type="xforms:ValueTemplate"/>
-                       </xsd:sequence>                 
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attribute name="resource" type="xsd:anyURI" use="optional"/>
-                       <xsd:attribute name="show" use="optional" default="replace">
-                               <xsd:simpleType>
-                                       <xsd:restriction base="xsd:string">
-                                               <xsd:enumeration value="new"/>
-                                               <xsd:enumeration value="replace"/>
-                                       </xsd:restriction>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="send">
-               <xsd:complexType>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attribute name="submission" type="xsd:IDREF" use="optional"/>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-       <xsd:element name="message">
-               <xsd:complexType mixed="true">
-                       <xsd:group ref="xforms:UI.Content"/>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       <xsd:attributeGroup ref="xforms:Single.Node.Binding.Attributes"/>
-                       <xsd:attribute name="level" use="optional" default="modal">
-                               <xsd:simpleType>
-                                       <xsd:union memberTypes="xforms:QNameButNotNCNAME">
-                                               <xsd:simpleType>
-                                                       <xsd:restriction base="xsd:string">
-                                                               <xsd:enumeration value="ephemeral"/>
-                                                               <xsd:enumeration value="modeless"/>
-                                                               <xsd:enumeration value="modal"/>
-                                                       </xsd:restriction>
-                                               </xsd:simpleType>
-                                       </xsd:union>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-                       <xsd:attributeGroup ref="xforms:XML.Events"/>
-                       <xsd:attributeGroup ref="xforms:Common.Action.Attributes"/>
-               </xsd:complexType>
-       </xsd:element>
-
-       <xsd:element name="submission">
-               <xsd:annotation>
-                       <xsd:documentation>submit info container.</xsd:documentation>
-               </xsd:annotation>
-               <xsd:complexType>
-                       <xsd:sequence>
-                               <!-- There should only be zero or one resource, zero or one method, and zero or more header 
-                                    We can't say exactly this, but we get as close as possible -->
-                               <xsd:choice minOccurs="0" maxOccurs="unbounded">
-                                       <xsd:element name="resource" type="xforms:ValueTemplate"/>
-                                       <xsd:element name="method" type="xforms:ValueTemplate"/>
-                                       <xsd:element name="header">
-                                               <xsd:complexType>
-                                                       <!-- Both name and value+ are required, but order independent -->
-                                                       <xsd:choice>
-                                                            <xsd:sequence>
-                                                                    <xsd:element name="name" type="xforms:ValueTemplate" />
-                                                                    <xsd:element name="value" type="xforms:ValueTemplate"
-                                        minOccurs="1" maxOccurs="unbounded" />
-                                                            </xsd:sequence>
-                                                            <xsd:sequence>
-                                                                    <xsd:element name="value" type="xforms:ValueTemplate"
-                                        minOccurs="1" maxOccurs="unbounded" />
-                                                                    <xsd:element name="name" type="xforms:ValueTemplate" />
-                                                            </xsd:sequence>
-                                                       </xsd:choice>
-                    <xsd:attribute name="combine" use="optional" default="append">
-                            <xsd:simpleType>
-                                    <xsd:restriction base="xsd:string">
-                                            <xsd:enumeration value="append"/>
-                                            <xsd:enumeration value="prepend"/>
-                                            <xsd:enumeration value="replace"/>
-                                    </xsd:restriction>
-                            </xsd:simpleType>
-                    </xsd:attribute>
-                                               </xsd:complexType>
-                                       </xsd:element>
-                               </xsd:choice>
-                               <!-- As is the case everywhere else, action handlers are last -->
-                               <xsd:group ref="xforms:Action"/>
-                       </xsd:sequence>
-                       <xsd:attributeGroup ref="xforms:Common.Attributes"/>
-                       
-                       <xsd:attribute name="ref" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="bind" type="xsd:IDREF" use="optional"/>
-                       
-                       <!-- Either the resource attribute, action attribute, or resource child element is required -->
-                       <xsd:attribute name="resource" type="xsd:anyURI" use="optional"/>
-                       <xsd:attribute name="action" type="xsd:anyURI" use="optional"/>
-                       
-                       <xsd:attribute name="mode" use="optional" default="asynchronous">
-                               <xsd:simpleType>
-                                       <xsd:restriction base="xsd:string">
-                                               <xsd:enumeration value="asynchronous"/>
-                                               <xsd:enumeration value="synchronous"/>
-                                       </xsd:restriction>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-
-                       <!-- Either the method attribute or the method child element is required -->
-                       <xsd:attribute name="method" use="optional">
-                               <xsd:simpleType>
-                                       <xsd:union memberTypes="xforms:QNameButNotNCNAME xsd:NCName">
-                                               <xsd:simpleType>
-                                                       <xsd:restriction base="xsd:string">
-                                                               <xsd:enumeration value="post"/>
-                                                               <xsd:enumeration value="put"/>
-                                                               <xsd:enumeration value="get"/>
-                                                               <xsd:enumeration value="delete"/>
-                                                               <xsd:enumeration value="multipart-post"/>
-                                                               <xsd:enumeration value="form-data-post"/>
-                                                               <xsd:enumeration value="urlencoded-post"/>
-                                                       </xsd:restriction>
-                                               </xsd:simpleType>
-                                       </xsd:union>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-
-                        <!-- The defaults for these are false if serialization is 'none' and true otherwise -->
-                       <xsd:attribute name="validate" type="xsd:boolean" use="optional"/>
-                       <xsd:attribute name="relevant" type="xsd:boolean" use="optional"/>
-                       
-                       <!-- The default is based on the selected method, e.g. application/xml for the post method -->
-                       <xsd:attribute name="serialization" type="xsd:string" use="optional"/>
-                       
-                       <xsd:attribute name="version" type="xsd:NMTOKEN" use="optional" default="1.0"/>
-                       <xsd:attribute name="indent" type="xsd:boolean" use="optional" default="false"/>
-                       <xsd:attribute name="mediatype" type="xsd:string" use="optional" default="application/xml"/>
-                       <xsd:attribute name="encoding" type="xsd:string" use="optional" default="UTF-8"/>
-                       
-                       <xsd:attribute name="omit-xml-declaration" type="xsd:boolean" use="optional" default="false"/>
-                       <!-- This is optional with no default because omitting the attribute behaves differently 
-                            than including it with any value -->
-                       <xsd:attribute name="standalone" type="xsd:boolean" use="optional"/>
-                       
-                       <xsd:attribute name="cdata-section-elements" type="xforms:QNameList" use="optional" default=""/>
-                       
-                       <xsd:attribute name="replace" use="optional" default="all">
-                               <xsd:simpleType>
-                                       <xsd:union memberTypes="xforms:QNameButNotNCNAME">
-                                               <xsd:simpleType>
-                                                       <xsd:restriction base="xsd:string">
-                                                               <xsd:enumeration value="all"/>
-                                                               <xsd:enumeration value="instance"/>
-                                                               <xsd:enumeration value="text"/>
-                                                               <xsd:enumeration value="none"/>
-                                                       </xsd:restriction>
-                                               </xsd:simpleType>
-                                       </xsd:union>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-                       
-                       <!-- Default is not specified because the default is to replace the instance being submitted -->
-                       <xsd:attribute name="instance" type="xsd:IDREF" use="optional"/>
-                       
-                       <xsd:attribute name="separator" use="optional" default="&amp;">
-                               <xsd:simpleType>
-                                       <xsd:restriction base="xsd:string">
-                                               <xsd:enumeration value="&amp;"/>
-                                               <xsd:enumeration value=";"/>
-                                       </xsd:restriction>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-                       
-                       <!-- Default is not specified because the defalut is to replace the whole instance indicated 
-                            by the instance attribute -->
-                       <xsd:attribute name="targetref" type="xforms:XPathExpression" use="optional"/>
-                       <xsd:attribute name="target" type="xforms:XPathExpression" use="optional"/>
-                       
-                       <!-- Default not specified because omitting the attribute behaves differently than
-                            including it with any value -->
-                       <xsd:attribute name="includenamespaceprefixes" use="optional">
-                               <xsd:simpleType>
-                                       <xsd:list>
-                                               <xsd:simpleType>
-                                                       <xsd:union memberTypes="xsd:NCName">
-                                                               <xsd:simpleType>
-                                                                       <xsd:restriction base="xsd:string">
-                                                                               <xsd:enumeration value="#default"/>
-                                                                       </xsd:restriction>
-                                                               </xsd:simpleType>
-                                                       </xsd:union>
-                                               </xsd:simpleType>
-                                       </xsd:list>
-                               </xsd:simpleType>
-                       </xsd:attribute>
-               </xsd:complexType>
-       </xsd:element>
-
-        <!-- 
-Internal helper types 
--->
-
-       <xsd:simpleType name="versionList">
-               <xsd:list itemType="xforms:versionNumber"/>
-       </xsd:simpleType>
-       <xsd:simpleType name="versionNumber">
-               <xsd:restriction base="xsd:string">
-                       <xsd:pattern value="[1-9]\d*\.\d+"/>
-               </xsd:restriction>
-       </xsd:simpleType>
-       <xsd:simpleType name="XPathExpression">
-               <xsd:restriction base="xsd:string"/>
-       </xsd:simpleType>
-       <xsd:simpleType name="QNameList">
-               <xsd:list itemType="xsd:QName"/>
-       </xsd:simpleType>
-       <xsd:simpleType name="anyURIList">
-               <xsd:list itemType="xsd:anyURI"/>
-       </xsd:simpleType>
-       <xsd:simpleType name="QNameButNotNCNAME">
-               <xsd:restriction base="xsd:QName">
-                       <xsd:pattern value="[^:]+:[^:]+"/>
-               </xsd:restriction>
-       </xsd:simpleType>
-       <xsd:simpleType name="appearanceType">
-               <xsd:union memberTypes="xforms:QNameButNotNCNAME">
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:enumeration value="full"/>
-                                       <xsd:enumeration value="compact"/>
-                                       <xsd:enumeration value="minimal"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-
-       <xsd:complexType name="ValueTemplate">
-               <xsd:simpleContent>
-                       <xsd:extension base="xsd:string">
-                               <xsd:attribute name="value" type="xforms:XPathExpression" use="optional"/>
-                       </xsd:extension>
-               </xsd:simpleContent>
-       </xsd:complexType>
-
-        <!--
-New simpleTypes provided to form authors
--->
-
-       <xsd:simpleType name="listItem">
-               <xsd:restriction base="xsd:string">
-                       <xsd:pattern value="\S+"/>
-               </xsd:restriction>
-       </xsd:simpleType>
-       <xsd:simpleType name="listItems">
-               <xsd:list itemType="xforms:listItem"/>
-        </xsd:simpleType>
-
-       <xsd:simpleType name="dateTime">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:dateTime"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="time">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:time"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="date">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:date"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="duration">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:duration"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="gYearMonth">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:gYearMonth"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="gYear">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:gYear"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="gMonthDay">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:gMonthDay"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="gDay">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:gDay"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="gMonth">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:gMonth"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="string">
-               <xsd:restriction base="xsd:string"/>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="boolean">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:boolean"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="base64Binary">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:base64Binary"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="hexBinary">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:hexBinary"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="float">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:float"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="decimal">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:decimal"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="double">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:double"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="anyURI">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:anyURI"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="QName">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:QName"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="normalizedString">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:normalizedString"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="token">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:token"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="language">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:language"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="Name">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:Name"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="NCName">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:NCName"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="ID">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:ID"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="IDREF">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:IDREF"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="IDREFS">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:IDREFS"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="NMTOKEN">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:NMTOKEN"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="NMTOKENS">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:NMTOKENS"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="integer">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:integer"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="negativeInteger">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:negativeInteger"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="long">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:long"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="int">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:int"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="short">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:short"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="byte">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:byte"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="nonNegativeInteger">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:nonNegativeInteger"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="unsignedLong">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:unsignedLong"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="unsignedInt">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:unsignedInt"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="unsignedShort">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:unsignedShort"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="unsignedByte">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:unsignedByte"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="positiveInteger">
-               <xsd:union>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:positiveInteger"/>
-                       </xsd:simpleType>
-                       <xsd:simpleType>
-                               <xsd:restriction base="xsd:string">
-                                       <xsd:length value="0"/>
-                               </xsd:restriction>
-                       </xsd:simpleType>
-               </xsd:union>
-       </xsd:simpleType>
-       
-       <xsd:simpleType name="dayTimeDuration">
-               <xsd:restriction base="xsd:duration">
-                       <xsd:pattern value="([\-]?P([0-9]+D(T([0-9]+(H([0-9]+(M([0-9]+(\.[0-9]*)?S
-                       |\.[0-9]+S)?|(\.[0-9]*)?S)|(\.[0-9]*)?S)?|M([0-9]+
-                       (\.[0-9]*)?S|\.[0-9]+S)?|(\.[0-9]*)?S)|\.[0-9]+S))?
-                       |T([0-9]+(H([0-9]+(M([0-9]+(\.[0-9]*)?S|\.[0-9]+S)?
-                       |(\.[0-9]*)?S)|(\.[0-9]*)?S)?|M([0-9]+(\.[0-9]*)?S|\.[0-9]+S)?
-                       |(\.[0-9]*)?S)|\.[0-9]+S)))?"/>
-               </xsd:restriction>
-       </xsd:simpleType>
-
-       <xsd:simpleType name="yearMonthDuration">
-               <xsd:restriction base="xsd:duration">
-                       <xsd:pattern value="([\-]?P[0-9]+(Y([0-9]+M)?|M))?"/>
-               </xsd:restriction>
-       </xsd:simpleType>
-       <xsd:simpleType name="email">
-               <xsd:restriction base="xsd:string">
-                       <xsd:pattern value="([A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+(\.[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+)*@[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+(\.[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+)*)?"/>
-               </xsd:restriction>
-       </xsd:simpleType>
-
-       <xsd:simpleType name="card-number">
-               <xsd:annotation>
-                       <xsd:documentation>
-                       This type defines the basic lexical properties for a dataypte that can be used to represent
-                       various ID numbers such as for debit and credit cards.
-                       This type does not apply the Luhn checksum algorithm.
-                       </xsd:documentation>
-               </xsd:annotation>
-               <xsd:restriction base="xsd:string">
-                       <xsd:pattern value="[0-9]*"/>
-               </xsd:restriction>
-       </xsd:simpleType>
-
-
-</xsd:schema>
diff --git a/org.argeo.cms/src/org/argeo/cms/acr/schemas/docbook.xsd b/org.argeo.cms/src/org/argeo/cms/acr/schemas/docbook.xsd
deleted file mode 100644 (file)
index f2c9aed..0000000
+++ /dev/null
@@ -1,17461 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:docbook="http://docbook.org/ns/docbook">
-  <xs:import namespace="http://www.w3.org/1999/xlink" schemaLocation="xlink.xsd"/>
-  <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>
-  <xs:attributeGroup name="db.common.attributes">
-    <xs:attribute ref="xml:id"/>
-    <xs:attribute name="version"/>
-    <xs:attribute ref="xml:lang"/>
-    <xs:attribute ref="xml:base"/>
-    <xs:attribute name="remap"/>
-    <xs:attribute name="xreflabel"/>
-    <xs:attribute name="revisionflag">
-      <xs:simpleType>
-        <xs:restriction base="xs:token">
-          <xs:enumeration value="changed"/>
-          <xs:enumeration value="added"/>
-          <xs:enumeration value="deleted"/>
-          <xs:enumeration value="off"/>
-        </xs:restriction>
-      </xs:simpleType>
-    </xs:attribute>
-    <xs:attribute name="dir">
-      <xs:simpleType>
-        <xs:restriction base="xs:token">
-          <xs:enumeration value="ltr"/>
-          <xs:enumeration value="rtl"/>
-          <xs:enumeration value="lro"/>
-          <xs:enumeration value="rlo"/>
-        </xs:restriction>
-      </xs:simpleType>
-    </xs:attribute>
-    <xs:attribute name="arch"/>
-    <xs:attribute name="audience"/>
-    <xs:attribute name="condition"/>
-    <xs:attribute name="conformance"/>
-    <xs:attribute name="os"/>
-    <xs:attribute name="revision"/>
-    <xs:attribute name="security"/>
-    <xs:attribute name="userlevel"/>
-    <xs:attribute name="vendor"/>
-    <xs:attribute name="wordsize"/>
-    <xs:attribute name="annotations"/>
-  </xs:attributeGroup>
-  <xs:attributeGroup name="db.common.linking.attributes">
-    <xs:attribute name="linkend" type="xs:IDREF"/>
-    <xs:attribute ref="xlink:href"/>
-    <xs:attribute ref="xlink:type"/>
-    <xs:attribute ref="xlink:role"/>
-    <xs:attribute ref="xlink:arcrole"/>
-    <xs:attribute ref="xlink:title"/>
-    <xs:attribute ref="xlink:show"/>
-    <xs:attribute ref="xlink:actuate"/>
-  </xs:attributeGroup>
-  <xs:element name="title">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="titleabbrev">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="subtitle">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="info">
-    <xs:complexType>
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:title"/>
-          <xs:element ref="docbook:titleabbrev"/>
-          <xs:element ref="docbook:subtitle"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:abstract"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:artpagenums"/>
-          <xs:element ref="docbook:author"/>
-          <xs:element ref="docbook:authorgroup"/>
-          <xs:element ref="docbook:authorinitials"/>
-          <xs:element ref="docbook:bibliocoverage"/>
-          <xs:element ref="docbook:biblioid"/>
-          <xs:element ref="docbook:bibliosource"/>
-          <xs:element ref="docbook:collab"/>
-          <xs:element ref="docbook:confgroup"/>
-          <xs:element ref="docbook:contractsponsor"/>
-          <xs:element ref="docbook:contractnum"/>
-          <xs:element ref="docbook:copyright"/>
-          <xs:element ref="docbook:cover"/>
-          <xs:element ref="docbook:date"/>
-          <xs:element ref="docbook:edition"/>
-          <xs:element ref="docbook:editor"/>
-          <xs:element ref="docbook:issuenum"/>
-          <xs:element ref="docbook:keywordset"/>
-          <xs:element ref="docbook:legalnotice"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:org"/>
-          <xs:element ref="docbook:orgname"/>
-          <xs:element ref="docbook:othercredit"/>
-          <xs:element ref="docbook:pagenums"/>
-          <xs:element ref="docbook:printhistory"/>
-          <xs:element ref="docbook:pubdate"/>
-          <xs:element ref="docbook:publisher"/>
-          <xs:element ref="docbook:publishername"/>
-          <xs:element ref="docbook:releaseinfo"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:seriesvolnums"/>
-          <xs:element ref="docbook:subjectset"/>
-          <xs:element ref="docbook:volumenum"/>
-          <xs:element ref="docbook:annotation"/>
-          <xs:element ref="docbook:extendedlink"/>
-          <xs:element ref="docbook:bibliomisc"/>
-          <xs:element ref="docbook:bibliomset"/>
-          <xs:element ref="docbook:bibliorelation"/>
-          <xs:element ref="docbook:biblioset"/>
-          <xs:element ref="docbook:itermset"/>
-          <xs:element ref="docbook:productname"/>
-          <xs:element ref="docbook:productnumber"/>
-        </xs:choice>
-        <xs:sequence>
-          <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
-        </xs:sequence>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="subjectset">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:subject"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="scheme" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="subject">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:subjectterm"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="weight"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="subjectterm">
-    <xs:complexType mixed="true">
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="keywordset">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:keyword"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="keyword">
-    <xs:complexType mixed="true">
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="procedure">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:step"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="step">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:sequence minOccurs="0">
-              <xs:choice>
-                <xs:element ref="docbook:substeps"/>
-                <xs:element ref="docbook:stepalternatives"/>
-              </xs:choice>
-              <xs:choice minOccurs="0" maxOccurs="unbounded">
-                <xs:element ref="docbook:itemizedlist"/>
-                <xs:element ref="docbook:orderedlist"/>
-                <xs:element ref="docbook:procedure"/>
-                <xs:element ref="docbook:simplelist"/>
-                <xs:element ref="docbook:variablelist"/>
-                <xs:element ref="docbook:segmentedlist"/>
-                <xs:element ref="docbook:glosslist"/>
-                <xs:element ref="docbook:bibliolist"/>
-                <xs:element ref="docbook:calloutlist"/>
-                <xs:element ref="docbook:qandaset"/>
-                <xs:element ref="docbook:example"/>
-                <xs:element ref="docbook:figure"/>
-                <xs:element ref="docbook:table"/>
-                <xs:element ref="docbook:equation"/>
-                <xs:element ref="docbook:informalexample"/>
-                <xs:element ref="docbook:informalfigure"/>
-                <xs:element ref="docbook:informaltable"/>
-                <xs:element ref="docbook:informalequation"/>
-                <xs:element ref="docbook:sidebar"/>
-                <xs:element ref="docbook:blockquote"/>
-                <xs:element ref="docbook:address"/>
-                <xs:element ref="docbook:epigraph"/>
-                <xs:element ref="docbook:mediaobject"/>
-                <xs:element ref="docbook:screenshot"/>
-                <xs:element ref="docbook:task"/>
-                <xs:element ref="docbook:productionset"/>
-                <xs:element ref="docbook:constraintdef"/>
-                <xs:element ref="docbook:msgset"/>
-                <xs:element ref="docbook:screen"/>
-                <xs:element ref="docbook:literallayout"/>
-                <xs:element ref="docbook:programlistingco"/>
-                <xs:element ref="docbook:screenco"/>
-                <xs:element ref="docbook:programlisting"/>
-                <xs:element ref="docbook:synopsis"/>
-                <xs:element ref="docbook:bridgehead"/>
-                <xs:element ref="docbook:remark"/>
-                <xs:element ref="docbook:revhistory"/>
-                <xs:element ref="docbook:indexterm"/>
-                <xs:element ref="docbook:funcsynopsis"/>
-                <xs:element ref="docbook:classsynopsis"/>
-                <xs:element ref="docbook:methodsynopsis"/>
-                <xs:element ref="docbook:constructorsynopsis"/>
-                <xs:element ref="docbook:destructorsynopsis"/>
-                <xs:element ref="docbook:fieldsynopsis"/>
-                <xs:element ref="docbook:cmdsynopsis"/>
-                <xs:element ref="docbook:caution"/>
-                <xs:element ref="docbook:important"/>
-                <xs:element ref="docbook:note"/>
-                <xs:element ref="docbook:tip"/>
-                <xs:element ref="docbook:warning"/>
-                <xs:element ref="docbook:anchor"/>
-                <xs:element ref="docbook:para"/>
-                <xs:element ref="docbook:formalpara"/>
-                <xs:element ref="docbook:simpara"/>
-                <xs:element ref="docbook:annotation"/>
-              </xs:choice>
-            </xs:sequence>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:choice>
-              <xs:element ref="docbook:substeps"/>
-              <xs:element ref="docbook:stepalternatives"/>
-            </xs:choice>
-            <xs:choice minOccurs="0" maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-          </xs:sequence>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="performance">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="optional"/>
-            <xs:enumeration value="required"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="stepalternatives">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:step"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="performance">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="optional"/>
-            <xs:enumeration value="required"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="substeps">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:step"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="performance">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="optional"/>
-            <xs:enumeration value="required"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="sidebar">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="abstract">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="personblurb">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="blockquote">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:attribution"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="attribution">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citation"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bridgehead">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="renderas">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="sect1"/>
-            <xs:enumeration value="sect2"/>
-            <xs:enumeration value="sect3"/>
-            <xs:enumeration value="sect4"/>
-            <xs:enumeration value="sect5"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherrenderas" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="remark">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="epigraph">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element minOccurs="0" ref="docbook:attribution"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:literallayout"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="footnote">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-        <xs:element ref="docbook:annotation"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="formalpara">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexterm"/>
-        <xs:element ref="docbook:para"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="para">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="simpara">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="itemizedlist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:listitem"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="spacing">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="compact"/>
-            <xs:enumeration value="normal"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="mark" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="orderedlist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:listitem"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="spacing">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="compact"/>
-            <xs:enumeration value="normal"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startingnumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="inheritnum">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="ignore"/>
-            <xs:enumeration value="inherit"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="numeration">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="arabic"/>
-            <xs:enumeration value="upperalpha"/>
-            <xs:enumeration value="loweralpha"/>
-            <xs:enumeration value="upperroman"/>
-            <xs:enumeration value="lowerroman"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="listitem">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-        <xs:element ref="docbook:annotation"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="override" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="segmentedlist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:segtitle"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:seglistitem"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="segtitle">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="seglistitem">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:seg"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="seg">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="simplelist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:member"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="type" default="vert">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="horiz"/>
-            <xs:enumeration value="vert"/>
-            <xs:enumeration value="inline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="columns" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="member">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="variablelist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:varlistentry"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="spacing">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="compact"/>
-            <xs:enumeration value="normal"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="termlength"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="varlistentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:term"/>
-        <xs:element ref="docbook:listitem"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="term">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="example">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:caption"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="floatstyle"/>
-      <xs:attribute name="width" type="xs:NMTOKEN"/>
-      <xs:attribute name="pgwide">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="informalexample">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:caption"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="floatstyle"/>
-      <xs:attribute name="width" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="literallayout">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:textobject"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:lineannotation"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="linenumbering">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="numbered"/>
-            <xs:enumeration value="unnumbered"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startinglinenumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="language"/>
-      <xs:attribute ref="xml:space"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="monospaced"/>
-            <xs:enumeration value="normal"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="screen">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:textobject"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:lineannotation"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="linenumbering">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="numbered"/>
-            <xs:enumeration value="unnumbered"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startinglinenumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="language"/>
-      <xs:attribute ref="xml:space"/>
-      <xs:attribute name="width" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="screenshot">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element ref="docbook:mediaobject"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="figure">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:caption"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="pgwide">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="floatstyle"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="informalfigure">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:caption"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="pgwide">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="floatstyle"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="mediaobject">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element minOccurs="0" ref="docbook:alt"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:videoobject"/>
-          <xs:element ref="docbook:audioobject"/>
-          <xs:element ref="docbook:imageobject"/>
-          <xs:element ref="docbook:textobject"/>
-          <xs:element ref="docbook:imageobjectco"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:caption"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="inlinemediaobject">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element minOccurs="0" ref="docbook:alt"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:videoobject"/>
-          <xs:element ref="docbook:audioobject"/>
-          <xs:element ref="docbook:imageobject"/>
-          <xs:element ref="docbook:textobject"/>
-          <xs:element ref="docbook:imageobjectco"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="videoobject">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element ref="docbook:videodata"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="audioobject">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element ref="docbook:audiodata"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="imageobject">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element ref="docbook:imagedata"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="textobject">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:choice>
-          <xs:element ref="docbook:phrase"/>
-          <xs:element ref="docbook:textdata"/>
-          <xs:choice maxOccurs="unbounded">
-            <xs:element ref="docbook:itemizedlist"/>
-            <xs:element ref="docbook:orderedlist"/>
-            <xs:element ref="docbook:procedure"/>
-            <xs:element ref="docbook:simplelist"/>
-            <xs:element ref="docbook:variablelist"/>
-            <xs:element ref="docbook:segmentedlist"/>
-            <xs:element ref="docbook:glosslist"/>
-            <xs:element ref="docbook:bibliolist"/>
-            <xs:element ref="docbook:calloutlist"/>
-            <xs:element ref="docbook:qandaset"/>
-            <xs:element ref="docbook:example"/>
-            <xs:element ref="docbook:figure"/>
-            <xs:element ref="docbook:table"/>
-            <xs:element ref="docbook:equation"/>
-            <xs:element ref="docbook:informalexample"/>
-            <xs:element ref="docbook:informalfigure"/>
-            <xs:element ref="docbook:informaltable"/>
-            <xs:element ref="docbook:informalequation"/>
-            <xs:element ref="docbook:sidebar"/>
-            <xs:element ref="docbook:blockquote"/>
-            <xs:element ref="docbook:address"/>
-            <xs:element ref="docbook:epigraph"/>
-            <xs:element ref="docbook:mediaobject"/>
-            <xs:element ref="docbook:screenshot"/>
-            <xs:element ref="docbook:task"/>
-            <xs:element ref="docbook:productionset"/>
-            <xs:element ref="docbook:constraintdef"/>
-            <xs:element ref="docbook:msgset"/>
-            <xs:element ref="docbook:screen"/>
-            <xs:element ref="docbook:literallayout"/>
-            <xs:element ref="docbook:programlistingco"/>
-            <xs:element ref="docbook:screenco"/>
-            <xs:element ref="docbook:programlisting"/>
-            <xs:element ref="docbook:synopsis"/>
-            <xs:element ref="docbook:bridgehead"/>
-            <xs:element ref="docbook:remark"/>
-            <xs:element ref="docbook:revhistory"/>
-            <xs:element ref="docbook:indexterm"/>
-            <xs:element ref="docbook:funcsynopsis"/>
-            <xs:element ref="docbook:classsynopsis"/>
-            <xs:element ref="docbook:methodsynopsis"/>
-            <xs:element ref="docbook:constructorsynopsis"/>
-            <xs:element ref="docbook:destructorsynopsis"/>
-            <xs:element ref="docbook:fieldsynopsis"/>
-            <xs:element ref="docbook:cmdsynopsis"/>
-            <xs:element ref="docbook:caution"/>
-            <xs:element ref="docbook:important"/>
-            <xs:element ref="docbook:note"/>
-            <xs:element ref="docbook:tip"/>
-            <xs:element ref="docbook:warning"/>
-            <xs:element ref="docbook:anchor"/>
-            <xs:element ref="docbook:para"/>
-            <xs:element ref="docbook:formalpara"/>
-            <xs:element ref="docbook:simpara"/>
-            <xs:element ref="docbook:annotation"/>
-          </xs:choice>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="videodata">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="format"/>
-      <xs:attribute name="fileref"/>
-      <xs:attribute name="entityref" type="xs:ENTITY"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="right"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="top"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="width"/>
-      <xs:attribute name="contentwidth"/>
-      <xs:attribute name="scalefit">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="scale" type="xs:NMTOKEN"/>
-      <xs:attribute name="depth"/>
-      <xs:attribute name="contentdepth"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="audiodata">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="format"/>
-      <xs:attribute name="fileref"/>
-      <xs:attribute name="entityref" type="xs:ENTITY"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="imagedata">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="format"/>
-      <xs:attribute name="fileref"/>
-      <xs:attribute name="entityref" type="xs:ENTITY"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="right"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="top"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="width"/>
-      <xs:attribute name="contentwidth"/>
-      <xs:attribute name="scalefit">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="scale" type="xs:NMTOKEN"/>
-      <xs:attribute name="depth"/>
-      <xs:attribute name="contentdepth"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="textdata">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="format"/>
-      <xs:attribute name="fileref"/>
-      <xs:attribute name="entityref" type="xs:ENTITY"/>
-      <xs:attribute name="encoding"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="caption">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-        <xs:element ref="docbook:annotation"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="address">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:pob"/>
-        <xs:element ref="docbook:street"/>
-        <xs:element ref="docbook:city"/>
-        <xs:element ref="docbook:state"/>
-        <xs:element ref="docbook:postcode"/>
-        <xs:element ref="docbook:country"/>
-        <xs:element ref="docbook:phone"/>
-        <xs:element ref="docbook:fax"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:otheraddr"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="linenumbering">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="numbered"/>
-            <xs:enumeration value="unnumbered"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startinglinenumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="language"/>
-      <xs:attribute ref="xml:space"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="street">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="pob">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="postcode">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="city">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="state">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="country">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="phone">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="fax">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="otheraddr">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="affiliation">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:shortaffil"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:jobtitle"/>
-        <xs:choice>
-          <xs:element minOccurs="0" ref="docbook:org"/>
-          <xs:sequence>
-            <xs:element minOccurs="0" ref="docbook:orgname"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:orgdiv"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:address"/>
-          </xs:sequence>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="shortaffil">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="jobtitle">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="orgname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="consortium"/>
-            <xs:enumeration value="corporation"/>
-            <xs:enumeration value="informal"/>
-            <xs:enumeration value="nonprofit"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherclass"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="orgdiv">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="artpagenums">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="personname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:honorific"/>
-        <xs:element ref="docbook:firstname"/>
-        <xs:element ref="docbook:surname"/>
-        <xs:element ref="docbook:lineage"/>
-        <xs:element ref="docbook:othername"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="author">
-    <xs:complexType>
-      <xs:choice>
-        <xs:sequence>
-          <xs:element ref="docbook:personname"/>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:personblurb"/>
-            <xs:element ref="docbook:affiliation"/>
-            <xs:element ref="docbook:email"/>
-            <xs:element ref="docbook:uri"/>
-            <xs:element ref="docbook:address"/>
-            <xs:element ref="docbook:contrib"/>
-          </xs:choice>
-        </xs:sequence>
-        <xs:sequence>
-          <xs:element ref="docbook:orgname"/>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:orgdiv"/>
-            <xs:element ref="docbook:affiliation"/>
-            <xs:element ref="docbook:email"/>
-            <xs:element ref="docbook:uri"/>
-            <xs:element ref="docbook:address"/>
-            <xs:element ref="docbook:contrib"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="authorgroup">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:othercredit"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="collab">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:person"/>
-          <xs:element ref="docbook:personname"/>
-          <xs:element ref="docbook:org"/>
-          <xs:element ref="docbook:orgname"/>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:affiliation"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="authorinitials">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="person">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:personname"/>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:affiliation"/>
-          <xs:element ref="docbook:email"/>
-          <xs:element ref="docbook:uri"/>
-          <xs:element ref="docbook:personblurb"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="org">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:orgname"/>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:affiliation"/>
-          <xs:element ref="docbook:email"/>
-          <xs:element ref="docbook:uri"/>
-          <xs:element ref="docbook:orgdiv"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="confgroup">
-    <xs:complexType>
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:confdates"/>
-        <xs:element ref="docbook:conftitle"/>
-        <xs:element ref="docbook:confnum"/>
-        <xs:element ref="docbook:confsponsor"/>
-        <xs:element ref="docbook:address"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="confdates">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="conftitle">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="confnum">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="confsponsor">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="contractnum">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="contractsponsor">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="copyright">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:year"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:holder"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="year">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="holder">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="cover">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="date">
-    <xs:complexType mixed="true">
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="edition">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="editor">
-    <xs:complexType>
-      <xs:choice>
-        <xs:sequence>
-          <xs:element ref="docbook:personname"/>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:personblurb"/>
-            <xs:element ref="docbook:affiliation"/>
-            <xs:element ref="docbook:email"/>
-            <xs:element ref="docbook:uri"/>
-            <xs:element ref="docbook:address"/>
-            <xs:element ref="docbook:contrib"/>
-          </xs:choice>
-        </xs:sequence>
-        <xs:sequence>
-          <xs:element ref="docbook:orgname"/>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:orgdiv"/>
-            <xs:element ref="docbook:affiliation"/>
-            <xs:element ref="docbook:email"/>
-            <xs:element ref="docbook:uri"/>
-            <xs:element ref="docbook:address"/>
-            <xs:element ref="docbook:contrib"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="biblioid">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="doi"/>
-            <xs:enumeration value="isbn"/>
-            <xs:enumeration value="isrn"/>
-            <xs:enumeration value="issn"/>
-            <xs:enumeration value="libraryofcongress"/>
-            <xs:enumeration value="pubsnumber"/>
-            <xs:enumeration value="uri"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherclass" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="citebiblioid">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="doi"/>
-            <xs:enumeration value="isbn"/>
-            <xs:enumeration value="isrn"/>
-            <xs:enumeration value="issn"/>
-            <xs:enumeration value="libraryofcongress"/>
-            <xs:enumeration value="pubsnumber"/>
-            <xs:enumeration value="uri"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherclass" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliosource">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="doi"/>
-            <xs:enumeration value="isbn"/>
-            <xs:enumeration value="isrn"/>
-            <xs:enumeration value="issn"/>
-            <xs:enumeration value="libraryofcongress"/>
-            <xs:enumeration value="pubsnumber"/>
-            <xs:enumeration value="uri"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherclass" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliorelation">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="doi"/>
-            <xs:enumeration value="isbn"/>
-            <xs:enumeration value="isrn"/>
-            <xs:enumeration value="issn"/>
-            <xs:enumeration value="libraryofcongress"/>
-            <xs:enumeration value="pubsnumber"/>
-            <xs:enumeration value="uri"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherclass" type="xs:NMTOKEN"/>
-      <xs:attribute name="type">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="hasformat"/>
-            <xs:enumeration value="haspart"/>
-            <xs:enumeration value="hasversion"/>
-            <xs:enumeration value="isformatof"/>
-            <xs:enumeration value="ispartof"/>
-            <xs:enumeration value="isreferencedby"/>
-            <xs:enumeration value="isreplacedby"/>
-            <xs:enumeration value="isrequiredby"/>
-            <xs:enumeration value="isversionof"/>
-            <xs:enumeration value="references"/>
-            <xs:enumeration value="replaces"/>
-            <xs:enumeration value="requires"/>
-            <xs:enumeration value="othertype"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="othertype" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliocoverage">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="spatial">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="dcmipoint"/>
-            <xs:enumeration value="iso3166"/>
-            <xs:enumeration value="dcmibox"/>
-            <xs:enumeration value="tgn"/>
-            <xs:enumeration value="otherspatial"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherspatial" type="xs:NMTOKEN"/>
-      <xs:attribute name="temporal">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="dcmiperiod"/>
-            <xs:enumeration value="w3c-dtf"/>
-            <xs:enumeration value="othertemporal"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="othertemporal" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="legalnotice">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="othercredit">
-    <xs:complexType>
-      <xs:choice>
-        <xs:sequence>
-          <xs:element ref="docbook:personname"/>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:personblurb"/>
-            <xs:element ref="docbook:affiliation"/>
-            <xs:element ref="docbook:email"/>
-            <xs:element ref="docbook:uri"/>
-            <xs:element ref="docbook:address"/>
-            <xs:element ref="docbook:contrib"/>
-          </xs:choice>
-        </xs:sequence>
-        <xs:sequence>
-          <xs:element ref="docbook:orgname"/>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:orgdiv"/>
-            <xs:element ref="docbook:affiliation"/>
-            <xs:element ref="docbook:email"/>
-            <xs:element ref="docbook:uri"/>
-            <xs:element ref="docbook:address"/>
-            <xs:element ref="docbook:contrib"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="copyeditor"/>
-            <xs:enumeration value="graphicdesigner"/>
-            <xs:enumeration value="other"/>
-            <xs:enumeration value="productioneditor"/>
-            <xs:enumeration value="technicaleditor"/>
-            <xs:enumeration value="translator"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherclass" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="pagenums">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="contrib">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="honorific">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="firstname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="surname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="lineage">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="othername">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="printhistory">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="pubdate">
-    <xs:complexType mixed="true">
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="publisher">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:publishername"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:address"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="publishername">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="releaseinfo">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="revhistory">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:revision"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="revision">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:revnumber"/>
-        <xs:element ref="docbook:date"/>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:authorinitials"/>
-          <xs:element ref="docbook:author"/>
-        </xs:choice>
-        <xs:choice minOccurs="0">
-          <xs:element ref="docbook:revremark"/>
-          <xs:element ref="docbook:revdescription"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="revnumber">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="revremark">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="revdescription">
-    <xs:complexType>
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-        <xs:element ref="docbook:annotation"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="seriesvolnums">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="volumenum">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="issuenum">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="package">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="email">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="lineannotation">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="parameter">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="command"/>
-            <xs:enumeration value="function"/>
-            <xs:enumeration value="option"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="replaceable">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="command"/>
-            <xs:enumeration value="function"/>
-            <xs:enumeration value="option"/>
-            <xs:enumeration value="parameter"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="uri">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="type"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="abbrev">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:trademark"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="acronym">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:trademark"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="citation">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="citerefentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:refentrytitle"/>
-        <xs:element minOccurs="0" ref="docbook:manvolnum"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refentrytitle">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="manvolnum">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="citetitle">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="pubwork">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="article"/>
-            <xs:enumeration value="bbs"/>
-            <xs:enumeration value="book"/>
-            <xs:enumeration value="cdrom"/>
-            <xs:enumeration value="chapter"/>
-            <xs:enumeration value="dvd"/>
-            <xs:enumeration value="emailmessage"/>
-            <xs:enumeration value="gopher"/>
-            <xs:enumeration value="journal"/>
-            <xs:enumeration value="manuscript"/>
-            <xs:enumeration value="newsposting"/>
-            <xs:enumeration value="part"/>
-            <xs:enumeration value="refentry"/>
-            <xs:enumeration value="section"/>
-            <xs:enumeration value="series"/>
-            <xs:enumeration value="set"/>
-            <xs:enumeration value="webpage"/>
-            <xs:enumeration value="wiki"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="emphasis">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="foreignphrase">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="phrase">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="quote">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="subscript">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="superscript">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="trademark">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="copyright"/>
-            <xs:enumeration value="registered"/>
-            <xs:enumeration value="service"/>
-            <xs:enumeration value="trade"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="wordasword">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="footnoteref">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="xref">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="xrefstyle"/>
-      <xs:attribute name="endterm" type="xs:IDREF"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="link">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="xrefstyle"/>
-      <xs:attribute name="endterm" type="xs:IDREF"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="olink">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="targetdoc"/>
-      <xs:attribute name="role"/>
-      <xs:attribute name="xrefstyle"/>
-      <xs:attribute name="localinfo"/>
-      <xs:attribute name="targetptr"/>
-      <xs:attribute name="type"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="anchor">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="alt">
-    <xs:complexType mixed="true">
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:inlinemediaobject"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="set">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:toc"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:set"/>
-          <xs:element ref="docbook:book"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:setindex"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="book">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-          <xs:element ref="docbook:dedication"/>
-          <xs:element ref="docbook:acknowledgements"/>
-          <xs:element ref="docbook:preface"/>
-          <xs:element ref="docbook:chapter"/>
-          <xs:element ref="docbook:appendix"/>
-          <xs:element ref="docbook:article"/>
-          <xs:element ref="docbook:colophon"/>
-          <xs:element ref="docbook:part"/>
-          <xs:element ref="docbook:reference"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="dedication">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="acknowledgements">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="colophon">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="appendix">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:glossary"/>
-            <xs:element ref="docbook:bibliography"/>
-            <xs:element ref="docbook:index"/>
-            <xs:element ref="docbook:toc"/>
-          </xs:choice>
-          <xs:choice>
-            <xs:sequence>
-              <xs:choice maxOccurs="unbounded">
-                <xs:element ref="docbook:itemizedlist"/>
-                <xs:element ref="docbook:orderedlist"/>
-                <xs:element ref="docbook:procedure"/>
-                <xs:element ref="docbook:simplelist"/>
-                <xs:element ref="docbook:variablelist"/>
-                <xs:element ref="docbook:segmentedlist"/>
-                <xs:element ref="docbook:glosslist"/>
-                <xs:element ref="docbook:bibliolist"/>
-                <xs:element ref="docbook:calloutlist"/>
-                <xs:element ref="docbook:qandaset"/>
-                <xs:element ref="docbook:example"/>
-                <xs:element ref="docbook:figure"/>
-                <xs:element ref="docbook:table"/>
-                <xs:element ref="docbook:equation"/>
-                <xs:element ref="docbook:informalexample"/>
-                <xs:element ref="docbook:informalfigure"/>
-                <xs:element ref="docbook:informaltable"/>
-                <xs:element ref="docbook:informalequation"/>
-                <xs:element ref="docbook:sidebar"/>
-                <xs:element ref="docbook:blockquote"/>
-                <xs:element ref="docbook:address"/>
-                <xs:element ref="docbook:epigraph"/>
-                <xs:element ref="docbook:mediaobject"/>
-                <xs:element ref="docbook:screenshot"/>
-                <xs:element ref="docbook:task"/>
-                <xs:element ref="docbook:productionset"/>
-                <xs:element ref="docbook:constraintdef"/>
-                <xs:element ref="docbook:msgset"/>
-                <xs:element ref="docbook:screen"/>
-                <xs:element ref="docbook:literallayout"/>
-                <xs:element ref="docbook:programlistingco"/>
-                <xs:element ref="docbook:screenco"/>
-                <xs:element ref="docbook:programlisting"/>
-                <xs:element ref="docbook:synopsis"/>
-                <xs:element ref="docbook:bridgehead"/>
-                <xs:element ref="docbook:remark"/>
-                <xs:element ref="docbook:revhistory"/>
-                <xs:element ref="docbook:indexterm"/>
-                <xs:element ref="docbook:funcsynopsis"/>
-                <xs:element ref="docbook:classsynopsis"/>
-                <xs:element ref="docbook:methodsynopsis"/>
-                <xs:element ref="docbook:constructorsynopsis"/>
-                <xs:element ref="docbook:destructorsynopsis"/>
-                <xs:element ref="docbook:fieldsynopsis"/>
-                <xs:element ref="docbook:cmdsynopsis"/>
-                <xs:element ref="docbook:caution"/>
-                <xs:element ref="docbook:important"/>
-                <xs:element ref="docbook:note"/>
-                <xs:element ref="docbook:tip"/>
-                <xs:element ref="docbook:warning"/>
-                <xs:element ref="docbook:anchor"/>
-                <xs:element ref="docbook:para"/>
-                <xs:element ref="docbook:formalpara"/>
-                <xs:element ref="docbook:simpara"/>
-                <xs:element ref="docbook:annotation"/>
-              </xs:choice>
-              <xs:choice minOccurs="0">
-                <xs:sequence>
-                  <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-                  <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-                </xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-                <xs:sequence>
-                  <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-                  <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-                </xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-              </xs:choice>
-            </xs:sequence>
-            <xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-            <xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-          </xs:choice>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:glossary"/>
-            <xs:element ref="docbook:bibliography"/>
-            <xs:element ref="docbook:index"/>
-            <xs:element ref="docbook:toc"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="chapter">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:glossary"/>
-            <xs:element ref="docbook:bibliography"/>
-            <xs:element ref="docbook:index"/>
-            <xs:element ref="docbook:toc"/>
-          </xs:choice>
-          <xs:choice>
-            <xs:sequence>
-              <xs:choice maxOccurs="unbounded">
-                <xs:element ref="docbook:itemizedlist"/>
-                <xs:element ref="docbook:orderedlist"/>
-                <xs:element ref="docbook:procedure"/>
-                <xs:element ref="docbook:simplelist"/>
-                <xs:element ref="docbook:variablelist"/>
-                <xs:element ref="docbook:segmentedlist"/>
-                <xs:element ref="docbook:glosslist"/>
-                <xs:element ref="docbook:bibliolist"/>
-                <xs:element ref="docbook:calloutlist"/>
-                <xs:element ref="docbook:qandaset"/>
-                <xs:element ref="docbook:example"/>
-                <xs:element ref="docbook:figure"/>
-                <xs:element ref="docbook:table"/>
-                <xs:element ref="docbook:equation"/>
-                <xs:element ref="docbook:informalexample"/>
-                <xs:element ref="docbook:informalfigure"/>
-                <xs:element ref="docbook:informaltable"/>
-                <xs:element ref="docbook:informalequation"/>
-                <xs:element ref="docbook:sidebar"/>
-                <xs:element ref="docbook:blockquote"/>
-                <xs:element ref="docbook:address"/>
-                <xs:element ref="docbook:epigraph"/>
-                <xs:element ref="docbook:mediaobject"/>
-                <xs:element ref="docbook:screenshot"/>
-                <xs:element ref="docbook:task"/>
-                <xs:element ref="docbook:productionset"/>
-                <xs:element ref="docbook:constraintdef"/>
-                <xs:element ref="docbook:msgset"/>
-                <xs:element ref="docbook:screen"/>
-                <xs:element ref="docbook:literallayout"/>
-                <xs:element ref="docbook:programlistingco"/>
-                <xs:element ref="docbook:screenco"/>
-                <xs:element ref="docbook:programlisting"/>
-                <xs:element ref="docbook:synopsis"/>
-                <xs:element ref="docbook:bridgehead"/>
-                <xs:element ref="docbook:remark"/>
-                <xs:element ref="docbook:revhistory"/>
-                <xs:element ref="docbook:indexterm"/>
-                <xs:element ref="docbook:funcsynopsis"/>
-                <xs:element ref="docbook:classsynopsis"/>
-                <xs:element ref="docbook:methodsynopsis"/>
-                <xs:element ref="docbook:constructorsynopsis"/>
-                <xs:element ref="docbook:destructorsynopsis"/>
-                <xs:element ref="docbook:fieldsynopsis"/>
-                <xs:element ref="docbook:cmdsynopsis"/>
-                <xs:element ref="docbook:caution"/>
-                <xs:element ref="docbook:important"/>
-                <xs:element ref="docbook:note"/>
-                <xs:element ref="docbook:tip"/>
-                <xs:element ref="docbook:warning"/>
-                <xs:element ref="docbook:anchor"/>
-                <xs:element ref="docbook:para"/>
-                <xs:element ref="docbook:formalpara"/>
-                <xs:element ref="docbook:simpara"/>
-                <xs:element ref="docbook:annotation"/>
-              </xs:choice>
-              <xs:choice minOccurs="0">
-                <xs:sequence>
-                  <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-                  <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-                </xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-                <xs:sequence>
-                  <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-                  <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-                </xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-              </xs:choice>
-            </xs:sequence>
-            <xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-            <xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-          </xs:choice>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:glossary"/>
-            <xs:element ref="docbook:bibliography"/>
-            <xs:element ref="docbook:index"/>
-            <xs:element ref="docbook:toc"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="part">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:partintro"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-          <xs:element ref="docbook:dedication"/>
-          <xs:element ref="docbook:acknowledgements"/>
-          <xs:element ref="docbook:preface"/>
-          <xs:element ref="docbook:chapter"/>
-          <xs:element ref="docbook:appendix"/>
-          <xs:element ref="docbook:article"/>
-          <xs:element ref="docbook:colophon"/>
-          <xs:element ref="docbook:refentry"/>
-          <xs:element ref="docbook:reference"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="preface">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:glossary"/>
-            <xs:element ref="docbook:bibliography"/>
-            <xs:element ref="docbook:index"/>
-            <xs:element ref="docbook:toc"/>
-          </xs:choice>
-          <xs:choice>
-            <xs:sequence>
-              <xs:choice maxOccurs="unbounded">
-                <xs:element ref="docbook:itemizedlist"/>
-                <xs:element ref="docbook:orderedlist"/>
-                <xs:element ref="docbook:procedure"/>
-                <xs:element ref="docbook:simplelist"/>
-                <xs:element ref="docbook:variablelist"/>
-                <xs:element ref="docbook:segmentedlist"/>
-                <xs:element ref="docbook:glosslist"/>
-                <xs:element ref="docbook:bibliolist"/>
-                <xs:element ref="docbook:calloutlist"/>
-                <xs:element ref="docbook:qandaset"/>
-                <xs:element ref="docbook:example"/>
-                <xs:element ref="docbook:figure"/>
-                <xs:element ref="docbook:table"/>
-                <xs:element ref="docbook:equation"/>
-                <xs:element ref="docbook:informalexample"/>
-                <xs:element ref="docbook:informalfigure"/>
-                <xs:element ref="docbook:informaltable"/>
-                <xs:element ref="docbook:informalequation"/>
-                <xs:element ref="docbook:sidebar"/>
-                <xs:element ref="docbook:blockquote"/>
-                <xs:element ref="docbook:address"/>
-                <xs:element ref="docbook:epigraph"/>
-                <xs:element ref="docbook:mediaobject"/>
-                <xs:element ref="docbook:screenshot"/>
-                <xs:element ref="docbook:task"/>
-                <xs:element ref="docbook:productionset"/>
-                <xs:element ref="docbook:constraintdef"/>
-                <xs:element ref="docbook:msgset"/>
-                <xs:element ref="docbook:screen"/>
-                <xs:element ref="docbook:literallayout"/>
-                <xs:element ref="docbook:programlistingco"/>
-                <xs:element ref="docbook:screenco"/>
-                <xs:element ref="docbook:programlisting"/>
-                <xs:element ref="docbook:synopsis"/>
-                <xs:element ref="docbook:bridgehead"/>
-                <xs:element ref="docbook:remark"/>
-                <xs:element ref="docbook:revhistory"/>
-                <xs:element ref="docbook:indexterm"/>
-                <xs:element ref="docbook:funcsynopsis"/>
-                <xs:element ref="docbook:classsynopsis"/>
-                <xs:element ref="docbook:methodsynopsis"/>
-                <xs:element ref="docbook:constructorsynopsis"/>
-                <xs:element ref="docbook:destructorsynopsis"/>
-                <xs:element ref="docbook:fieldsynopsis"/>
-                <xs:element ref="docbook:cmdsynopsis"/>
-                <xs:element ref="docbook:caution"/>
-                <xs:element ref="docbook:important"/>
-                <xs:element ref="docbook:note"/>
-                <xs:element ref="docbook:tip"/>
-                <xs:element ref="docbook:warning"/>
-                <xs:element ref="docbook:anchor"/>
-                <xs:element ref="docbook:para"/>
-                <xs:element ref="docbook:formalpara"/>
-                <xs:element ref="docbook:simpara"/>
-                <xs:element ref="docbook:annotation"/>
-              </xs:choice>
-              <xs:choice minOccurs="0">
-                <xs:sequence>
-                  <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-                  <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-                </xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-                <xs:sequence>
-                  <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-                  <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-                </xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-              </xs:choice>
-            </xs:sequence>
-            <xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-            <xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-          </xs:choice>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:glossary"/>
-            <xs:element ref="docbook:bibliography"/>
-            <xs:element ref="docbook:index"/>
-            <xs:element ref="docbook:toc"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="partintro">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="section">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-              <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="simplesect">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="article">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-          <xs:element ref="docbook:appendix"/>
-          <xs:element ref="docbook:acknowledgements"/>
-          <xs:element ref="docbook:colophon"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:section"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:sect1"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-          <xs:element ref="docbook:appendix"/>
-          <xs:element ref="docbook:acknowledgements"/>
-          <xs:element ref="docbook:colophon"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="faq"/>
-            <xs:enumeration value="journalarticle"/>
-            <xs:enumeration value="productsheet"/>
-            <xs:enumeration value="specification"/>
-            <xs:enumeration value="techreport"/>
-            <xs:enumeration value="whitepaper"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="annotation">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attribute name="annotates"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="extendedlink">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:locator"/>
-        <xs:element ref="docbook:arc"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="locator">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute ref="xlink:label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="arc">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute ref="xlink:from"/>
-      <xs:attribute ref="xlink:to"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="sect1">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:sect2"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:sect2"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="sect2">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:sect3"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:sect3"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="sect3">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:sect4"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:sect4"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="sect4">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element maxOccurs="unbounded" ref="docbook:sect5"/>
-                <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-              </xs:sequence>
-              <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:sect5"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="sect5">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:simplesect"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplesect"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:glossary"/>
-          <xs:element ref="docbook:bibliography"/>
-          <xs:element ref="docbook:index"/>
-          <xs:element ref="docbook:toc"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="reference">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:partintro"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:refentry"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="status"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexterm"/>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element minOccurs="0" ref="docbook:refmeta"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:refnamediv"/>
-        <xs:element minOccurs="0" ref="docbook:refsynopsisdiv"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:refsection"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:refsect1"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="status"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refmeta">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexterm"/>
-        <xs:element ref="docbook:refentrytitle"/>
-        <xs:element minOccurs="0" ref="docbook:manvolnum"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:refmiscinfo"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexterm"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refmiscinfo">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="source"/>
-            <xs:enumeration value="version"/>
-            <xs:enumeration value="manual"/>
-            <xs:enumeration value="sectdesc"/>
-            <xs:enumeration value="software"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherclass"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refnamediv">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:refdescriptor"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:refname"/>
-        <xs:element ref="docbook:refpurpose"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:refclass"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refdescriptor">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refpurpose">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refclass">
-    <xs:complexType mixed="true">
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:application"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refsynopsisdiv">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:choice minOccurs="0">
-              <xs:element maxOccurs="unbounded" ref="docbook:refsection"/>
-              <xs:element maxOccurs="unbounded" ref="docbook:refsect2"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:refsection"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:refsect2"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refsection">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:refsection"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:refsection"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="status"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refsect1">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:refsect2"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:refsect2"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refsect2">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:sequence>
-            <xs:choice maxOccurs="unbounded">
-              <xs:element ref="docbook:itemizedlist"/>
-              <xs:element ref="docbook:orderedlist"/>
-              <xs:element ref="docbook:procedure"/>
-              <xs:element ref="docbook:simplelist"/>
-              <xs:element ref="docbook:variablelist"/>
-              <xs:element ref="docbook:segmentedlist"/>
-              <xs:element ref="docbook:glosslist"/>
-              <xs:element ref="docbook:bibliolist"/>
-              <xs:element ref="docbook:calloutlist"/>
-              <xs:element ref="docbook:qandaset"/>
-              <xs:element ref="docbook:example"/>
-              <xs:element ref="docbook:figure"/>
-              <xs:element ref="docbook:table"/>
-              <xs:element ref="docbook:equation"/>
-              <xs:element ref="docbook:informalexample"/>
-              <xs:element ref="docbook:informalfigure"/>
-              <xs:element ref="docbook:informaltable"/>
-              <xs:element ref="docbook:informalequation"/>
-              <xs:element ref="docbook:sidebar"/>
-              <xs:element ref="docbook:blockquote"/>
-              <xs:element ref="docbook:address"/>
-              <xs:element ref="docbook:epigraph"/>
-              <xs:element ref="docbook:mediaobject"/>
-              <xs:element ref="docbook:screenshot"/>
-              <xs:element ref="docbook:task"/>
-              <xs:element ref="docbook:productionset"/>
-              <xs:element ref="docbook:constraintdef"/>
-              <xs:element ref="docbook:msgset"/>
-              <xs:element ref="docbook:screen"/>
-              <xs:element ref="docbook:literallayout"/>
-              <xs:element ref="docbook:programlistingco"/>
-              <xs:element ref="docbook:screenco"/>
-              <xs:element ref="docbook:programlisting"/>
-              <xs:element ref="docbook:synopsis"/>
-              <xs:element ref="docbook:bridgehead"/>
-              <xs:element ref="docbook:remark"/>
-              <xs:element ref="docbook:revhistory"/>
-              <xs:element ref="docbook:indexterm"/>
-              <xs:element ref="docbook:funcsynopsis"/>
-              <xs:element ref="docbook:classsynopsis"/>
-              <xs:element ref="docbook:methodsynopsis"/>
-              <xs:element ref="docbook:constructorsynopsis"/>
-              <xs:element ref="docbook:destructorsynopsis"/>
-              <xs:element ref="docbook:fieldsynopsis"/>
-              <xs:element ref="docbook:cmdsynopsis"/>
-              <xs:element ref="docbook:caution"/>
-              <xs:element ref="docbook:important"/>
-              <xs:element ref="docbook:note"/>
-              <xs:element ref="docbook:tip"/>
-              <xs:element ref="docbook:warning"/>
-              <xs:element ref="docbook:anchor"/>
-              <xs:element ref="docbook:para"/>
-              <xs:element ref="docbook:formalpara"/>
-              <xs:element ref="docbook:simpara"/>
-              <xs:element ref="docbook:annotation"/>
-            </xs:choice>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:refsect3"/>
-          </xs:sequence>
-          <xs:element maxOccurs="unbounded" ref="docbook:refsect3"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="refsect3">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glosslist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence minOccurs="0">
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:glossentry"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glossentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element minOccurs="0" ref="docbook:acronym"/>
-        <xs:element minOccurs="0" ref="docbook:abbrev"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexterm"/>
-        <xs:choice>
-          <xs:element ref="docbook:glosssee"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:glossdef"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="sortas"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glossdef">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:glossseealso"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="subject"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glosssee">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="otherterm" type="xs:IDREF"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glossseealso">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="otherterm" type="xs:IDREF"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="firstterm">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="baseform"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glossterm">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="baseform"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glossary">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:glossdiv"/>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:glossentry"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:bibliography"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="glossdiv">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:glossentry"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="termdef">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attribute name="sortas"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="baseform"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="biblioentry">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:abstract"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:artpagenums"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:authorgroup"/>
-        <xs:element ref="docbook:authorinitials"/>
-        <xs:element ref="docbook:bibliocoverage"/>
-        <xs:element ref="docbook:biblioid"/>
-        <xs:element ref="docbook:bibliosource"/>
-        <xs:element ref="docbook:collab"/>
-        <xs:element ref="docbook:confgroup"/>
-        <xs:element ref="docbook:contractsponsor"/>
-        <xs:element ref="docbook:contractnum"/>
-        <xs:element ref="docbook:copyright"/>
-        <xs:element ref="docbook:cover"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:edition"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:issuenum"/>
-        <xs:element ref="docbook:keywordset"/>
-        <xs:element ref="docbook:legalnotice"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:othercredit"/>
-        <xs:element ref="docbook:pagenums"/>
-        <xs:element ref="docbook:printhistory"/>
-        <xs:element ref="docbook:pubdate"/>
-        <xs:element ref="docbook:publisher"/>
-        <xs:element ref="docbook:publishername"/>
-        <xs:element ref="docbook:releaseinfo"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:seriesvolnums"/>
-        <xs:element ref="docbook:subjectset"/>
-        <xs:element ref="docbook:volumenum"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:extendedlink"/>
-        <xs:element ref="docbook:bibliomisc"/>
-        <xs:element ref="docbook:bibliomset"/>
-        <xs:element ref="docbook:bibliorelation"/>
-        <xs:element ref="docbook:biblioset"/>
-        <xs:element ref="docbook:itermset"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personblurb"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:subtitle"/>
-        <xs:element ref="docbook:title"/>
-        <xs:element ref="docbook:titleabbrev"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliomixed">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:abstract"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:artpagenums"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:authorgroup"/>
-        <xs:element ref="docbook:authorinitials"/>
-        <xs:element ref="docbook:bibliocoverage"/>
-        <xs:element ref="docbook:biblioid"/>
-        <xs:element ref="docbook:bibliosource"/>
-        <xs:element ref="docbook:collab"/>
-        <xs:element ref="docbook:confgroup"/>
-        <xs:element ref="docbook:contractsponsor"/>
-        <xs:element ref="docbook:contractnum"/>
-        <xs:element ref="docbook:copyright"/>
-        <xs:element ref="docbook:cover"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:edition"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:issuenum"/>
-        <xs:element ref="docbook:keywordset"/>
-        <xs:element ref="docbook:legalnotice"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:othercredit"/>
-        <xs:element ref="docbook:pagenums"/>
-        <xs:element ref="docbook:printhistory"/>
-        <xs:element ref="docbook:pubdate"/>
-        <xs:element ref="docbook:publisher"/>
-        <xs:element ref="docbook:publishername"/>
-        <xs:element ref="docbook:releaseinfo"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:seriesvolnums"/>
-        <xs:element ref="docbook:subjectset"/>
-        <xs:element ref="docbook:volumenum"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:extendedlink"/>
-        <xs:element ref="docbook:bibliomisc"/>
-        <xs:element ref="docbook:bibliomset"/>
-        <xs:element ref="docbook:bibliorelation"/>
-        <xs:element ref="docbook:biblioset"/>
-        <xs:element ref="docbook:itermset"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personblurb"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:subtitle"/>
-        <xs:element ref="docbook:title"/>
-        <xs:element ref="docbook:titleabbrev"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="biblioset">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:abstract"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:artpagenums"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:authorgroup"/>
-        <xs:element ref="docbook:authorinitials"/>
-        <xs:element ref="docbook:bibliocoverage"/>
-        <xs:element ref="docbook:biblioid"/>
-        <xs:element ref="docbook:bibliosource"/>
-        <xs:element ref="docbook:collab"/>
-        <xs:element ref="docbook:confgroup"/>
-        <xs:element ref="docbook:contractsponsor"/>
-        <xs:element ref="docbook:contractnum"/>
-        <xs:element ref="docbook:copyright"/>
-        <xs:element ref="docbook:cover"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:edition"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:issuenum"/>
-        <xs:element ref="docbook:keywordset"/>
-        <xs:element ref="docbook:legalnotice"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:othercredit"/>
-        <xs:element ref="docbook:pagenums"/>
-        <xs:element ref="docbook:printhistory"/>
-        <xs:element ref="docbook:pubdate"/>
-        <xs:element ref="docbook:publisher"/>
-        <xs:element ref="docbook:publishername"/>
-        <xs:element ref="docbook:releaseinfo"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:seriesvolnums"/>
-        <xs:element ref="docbook:subjectset"/>
-        <xs:element ref="docbook:volumenum"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:extendedlink"/>
-        <xs:element ref="docbook:bibliomisc"/>
-        <xs:element ref="docbook:bibliomset"/>
-        <xs:element ref="docbook:bibliorelation"/>
-        <xs:element ref="docbook:biblioset"/>
-        <xs:element ref="docbook:itermset"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personblurb"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:subtitle"/>
-        <xs:element ref="docbook:title"/>
-        <xs:element ref="docbook:titleabbrev"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="relation"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliomset">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:abstract"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:artpagenums"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:authorgroup"/>
-        <xs:element ref="docbook:authorinitials"/>
-        <xs:element ref="docbook:bibliocoverage"/>
-        <xs:element ref="docbook:biblioid"/>
-        <xs:element ref="docbook:bibliosource"/>
-        <xs:element ref="docbook:collab"/>
-        <xs:element ref="docbook:confgroup"/>
-        <xs:element ref="docbook:contractsponsor"/>
-        <xs:element ref="docbook:contractnum"/>
-        <xs:element ref="docbook:copyright"/>
-        <xs:element ref="docbook:cover"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:edition"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:issuenum"/>
-        <xs:element ref="docbook:keywordset"/>
-        <xs:element ref="docbook:legalnotice"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:othercredit"/>
-        <xs:element ref="docbook:pagenums"/>
-        <xs:element ref="docbook:printhistory"/>
-        <xs:element ref="docbook:pubdate"/>
-        <xs:element ref="docbook:publisher"/>
-        <xs:element ref="docbook:publishername"/>
-        <xs:element ref="docbook:releaseinfo"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:seriesvolnums"/>
-        <xs:element ref="docbook:subjectset"/>
-        <xs:element ref="docbook:volumenum"/>
-        <xs:element ref="docbook:extendedlink"/>
-        <xs:element ref="docbook:bibliomisc"/>
-        <xs:element ref="docbook:bibliomset"/>
-        <xs:element ref="docbook:bibliorelation"/>
-        <xs:element ref="docbook:biblioset"/>
-        <xs:element ref="docbook:itermset"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personblurb"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:subtitle"/>
-        <xs:element ref="docbook:title"/>
-        <xs:element ref="docbook:titleabbrev"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="relation"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliomisc">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliography">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:bibliodiv"/>
-          <xs:choice maxOccurs="unbounded">
-            <xs:element ref="docbook:biblioentry"/>
-            <xs:element ref="docbook:bibliomixed"/>
-          </xs:choice>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliodiv">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:biblioentry"/>
-          <xs:element ref="docbook:bibliomixed"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="bibliolist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence minOccurs="0">
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:biblioentry"/>
-          <xs:element ref="docbook:bibliomixed"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="biblioref">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="xrefstyle"/>
-      <xs:attribute name="endterm" type="xs:IDREF"/>
-      <xs:attribute name="units" type="xs:NMTOKEN"/>
-      <xs:attribute name="begin" type="xs:NMTOKEN"/>
-      <xs:attribute name="end" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="itermset">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:indexterm"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="indexterm">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:primary"/>
-        <xs:choice minOccurs="0">
-          <xs:sequence>
-            <xs:element ref="docbook:secondary"/>
-            <xs:choice minOccurs="0">
-              <xs:sequence>
-                <xs:element ref="docbook:tertiary"/>
-                <xs:choice minOccurs="0">
-                  <xs:element ref="docbook:see"/>
-                  <xs:element maxOccurs="unbounded" ref="docbook:seealso"/>
-                </xs:choice>
-              </xs:sequence>
-              <xs:element ref="docbook:see"/>
-              <xs:element maxOccurs="unbounded" ref="docbook:seealso"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:element ref="docbook:see"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:seealso"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="significance">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="normal"/>
-            <xs:enumeration value="preferred"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startref" type="xs:IDREF"/>
-      <xs:attribute name="zone" type="xs:IDREFS"/>
-      <xs:attribute name="pagenum"/>
-      <xs:attribute name="scope">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="all"/>
-            <xs:enumeration value="global"/>
-            <xs:enumeration value="local"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="type"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="singular"/>
-            <xs:enumeration value="startofrange"/>
-            <xs:enumeration value="endofrange"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="primary">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="sortas"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="secondary">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="sortas"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tertiary">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="sortas"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="see">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="seealso">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="index">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexdiv"/>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexentry"/>
-          <xs:element ref="docbook:segmentedlist"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-      <xs:attribute name="type"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="setindex">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexdiv"/>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexentry"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-      <xs:attribute name="type"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="indexdiv">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:indexentry"/>
-          <xs:element ref="docbook:segmentedlist"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="status"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="indexentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:primaryie"/>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:seeie"/>
-          <xs:element ref="docbook:seealsoie"/>
-        </xs:choice>
-        <xs:sequence minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:secondaryie"/>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:seeie"/>
-            <xs:element ref="docbook:seealsoie"/>
-            <xs:element ref="docbook:tertiaryie"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="primaryie">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="linkends" type="xs:IDREFS"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="secondaryie">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="linkends" type="xs:IDREFS"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tertiaryie">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="linkends" type="xs:IDREFS"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="seeie">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="seealsoie">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="linkends" type="xs:IDREFS"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="toc">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:tocdiv"/>
-          <xs:element ref="docbook:tocentry"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tocdiv">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:tocdiv"/>
-          <xs:element ref="docbook:tocentry"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="pagenum"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tocentry">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="pagenum"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="task">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-            <xs:element ref="docbook:subtitle"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:tasksummary"/>
-        <xs:element minOccurs="0" ref="docbook:taskprerequisites"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:example"/>
-        <xs:element minOccurs="0" ref="docbook:taskrelated"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tasksummary">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="taskprerequisites">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="taskrelated">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="calloutlist">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:callout"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="callout">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-        <xs:element ref="docbook:annotation"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="arearefs" use="required" type="xs:IDREFS"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="programlistingco">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element ref="docbook:areaspec"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:calloutlist"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="areaspec">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:area"/>
-        <xs:element ref="docbook:areaset"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="units">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="calspair"/>
-            <xs:enumeration value="linecolumn"/>
-            <xs:enumeration value="linecolumnpair"/>
-            <xs:enumeration value="linerange"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherunits" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="area">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:alt"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="units">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="calspair"/>
-            <xs:enumeration value="linecolumn"/>
-            <xs:enumeration value="linecolumnpair"/>
-            <xs:enumeration value="linerange"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherunits" type="xs:NMTOKEN"/>
-      <xs:attribute name="linkends" type="xs:IDREFS"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="coords" use="required"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="areaset">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:area"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="units">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="calspair"/>
-            <xs:enumeration value="linecolumn"/>
-            <xs:enumeration value="linecolumnpair"/>
-            <xs:enumeration value="linerange"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherunits" type="xs:NMTOKEN"/>
-      <xs:attribute name="linkends" type="xs:IDREFS"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="screenco">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element ref="docbook:areaspec"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:calloutlist"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="imageobjectco">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element ref="docbook:areaspec"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:imageobject"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:calloutlist"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="co">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="linkends" type="xs:IDREFS"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="coref">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="productionset">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:production"/>
-          <xs:element ref="docbook:productionrecap"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="production">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:lhs"/>
-        <xs:element ref="docbook:rhs"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:constraint"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="lhs">
-    <xs:complexType mixed="true">
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="rhs">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:lineannotation"/>
-        <xs:element ref="docbook:sbr"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="nonterminal">
-    <xs:complexType mixed="true">
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="def" use="required"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="constraint">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="productionrecap">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="constraintdef">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tgroup">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:colspec"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:spanspec"/>
-        <xs:element minOccurs="0" ref="docbook:thead"/>
-        <xs:element minOccurs="0" ref="docbook:tfoot"/>
-        <xs:element ref="docbook:tbody"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="tgroupstyle"/>
-      <xs:attribute name="cols" use="required" type="xs:NMTOKEN"/>
-      <xs:attribute name="colsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="right"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="colspec">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="colnum" type="xs:NMTOKEN"/>
-      <xs:attribute name="char"/>
-      <xs:attribute name="colsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="colwidth"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="colname"/>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="right"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="spanspec">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="spanname" use="required"/>
-      <xs:attribute name="namest" use="required"/>
-      <xs:attribute name="nameend" use="required"/>
-      <xs:attribute name="char"/>
-      <xs:attribute name="colsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="right"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="thead">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:colspec"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:row"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:tr"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tfoot">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:colspec"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:row"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:tr"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tbody">
-    <xs:complexType>
-      <xs:choice>
-        <xs:element maxOccurs="unbounded" ref="docbook:row"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:tr"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="row">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:entry"/>
-        <xs:element ref="docbook:entrytbl"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="top"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="entry">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="top"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="colsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="morerows" type="xs:NMTOKEN"/>
-      <xs:attribute name="colname"/>
-      <xs:attribute name="namest"/>
-      <xs:attribute name="spanname"/>
-      <xs:attribute name="nameend"/>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rotate">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="right"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="entrytbl">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:colspec"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:spanspec"/>
-        <xs:element minOccurs="0" ref="docbook:thead"/>
-        <xs:element ref="docbook:tbody"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="colname"/>
-      <xs:attribute name="namest"/>
-      <xs:attribute name="spanname"/>
-      <xs:attribute name="nameend"/>
-      <xs:attribute name="tgroupstyle"/>
-      <xs:attribute name="cols" type="xs:NMTOKEN"/>
-      <xs:attribute name="colsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="right"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="table">
-    <xs:complexType>
-      <xs:choice>
-        <xs:sequence>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-          <xs:sequence>
-            <xs:element ref="docbook:title"/>
-            <xs:element minOccurs="0" ref="docbook:titleabbrev"/>
-          </xs:sequence>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:indexterm"/>
-          <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:textobject"/>
-          <xs:choice>
-            <xs:element maxOccurs="unbounded" ref="docbook:mediaobject"/>
-            <xs:element maxOccurs="unbounded" ref="docbook:tgroup"/>
-          </xs:choice>
-        </xs:sequence>
-        <xs:sequence>
-          <xs:element ref="docbook:caption"/>
-          <xs:choice>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:col"/>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:colgroup"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:thead"/>
-          <xs:element minOccurs="0" ref="docbook:tfoot"/>
-          <xs:choice>
-            <xs:element maxOccurs="unbounded" ref="docbook:tbody"/>
-            <xs:element maxOccurs="unbounded" ref="docbook:tr"/>
-          </xs:choice>
-        </xs:sequence>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attribute name="label"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="tabstyle"/>
-      <xs:attribute name="floatstyle"/>
-      <xs:attribute name="orient">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="land"/>
-            <xs:enumeration value="port"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="colsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="frame">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="all"/>
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="none"/>
-            <xs:enumeration value="sides"/>
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="topbot"/>
-            <xs:enumeration value="void"/>
-            <xs:enumeration value="above"/>
-            <xs:enumeration value="below"/>
-            <xs:enumeration value="hsides"/>
-            <xs:enumeration value="lhs"/>
-            <xs:enumeration value="rhs"/>
-            <xs:enumeration value="vsides"/>
-            <xs:enumeration value="box"/>
-            <xs:enumeration value="border"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="pgwide">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="shortentry">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="tocentry">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowheader">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="firstcol"/>
-            <xs:enumeration value="norowheader"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="summary"/>
-      <xs:attribute name="width"/>
-      <xs:attribute name="border" type="xs:NMTOKEN"/>
-      <xs:attribute name="rules">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="none"/>
-            <xs:enumeration value="groups"/>
-            <xs:enumeration value="rows"/>
-            <xs:enumeration value="cols"/>
-            <xs:enumeration value="all"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="cellspacing"/>
-      <xs:attribute name="cellpadding"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="informaltable">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:choice>
-          <xs:sequence>
-            <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:textobject"/>
-            <xs:choice>
-              <xs:element maxOccurs="unbounded" ref="docbook:mediaobject"/>
-              <xs:element maxOccurs="unbounded" ref="docbook:tgroup"/>
-            </xs:choice>
-          </xs:sequence>
-          <xs:sequence>
-            <xs:choice>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:col"/>
-              <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:colgroup"/>
-            </xs:choice>
-            <xs:element minOccurs="0" ref="docbook:thead"/>
-            <xs:element minOccurs="0" ref="docbook:tfoot"/>
-            <xs:choice>
-              <xs:element maxOccurs="unbounded" ref="docbook:tbody"/>
-              <xs:element maxOccurs="unbounded" ref="docbook:tr"/>
-            </xs:choice>
-          </xs:sequence>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="tabstyle"/>
-      <xs:attribute name="floatstyle"/>
-      <xs:attribute name="orient">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="land"/>
-            <xs:enumeration value="port"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="colsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowsep">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="frame">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="all"/>
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="none"/>
-            <xs:enumeration value="sides"/>
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="topbot"/>
-            <xs:enumeration value="void"/>
-            <xs:enumeration value="above"/>
-            <xs:enumeration value="below"/>
-            <xs:enumeration value="hsides"/>
-            <xs:enumeration value="lhs"/>
-            <xs:enumeration value="rhs"/>
-            <xs:enumeration value="vsides"/>
-            <xs:enumeration value="box"/>
-            <xs:enumeration value="border"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="pgwide">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowheader">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="firstcol"/>
-            <xs:enumeration value="norowheader"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="summary"/>
-      <xs:attribute name="width"/>
-      <xs:attribute name="border" type="xs:NMTOKEN"/>
-      <xs:attribute name="rules">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="none"/>
-            <xs:enumeration value="groups"/>
-            <xs:enumeration value="rows"/>
-            <xs:enumeration value="cols"/>
-            <xs:enumeration value="all"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="cellspacing"/>
-      <xs:attribute name="cellpadding"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="col">
-    <xs:complexType>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="span" type="xs:NMTOKEN"/>
-      <xs:attribute name="width"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="colgroup">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:col"/>
-      </xs:sequence>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="span" type="xs:NMTOKEN"/>
-      <xs:attribute name="width"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tr">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:th"/>
-        <xs:element ref="docbook:td"/>
-      </xs:choice>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="th">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-      </xs:choice>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="abbr"/>
-      <xs:attribute name="axis"/>
-      <xs:attribute name="headers"/>
-      <xs:attribute name="scope">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="row"/>
-            <xs:enumeration value="col"/>
-            <xs:enumeration value="rowgroup"/>
-            <xs:enumeration value="colgroup"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowspan" type="xs:NMTOKEN"/>
-      <xs:attribute name="colspan" type="xs:NMTOKEN"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="td">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-      </xs:choice>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attribute name="class"/>
-      <xs:attribute name="style"/>
-      <xs:attribute name="title"/>
-      <xs:attribute name="lang"/>
-      <xs:attribute name="onclick"/>
-      <xs:attribute name="ondblclick"/>
-      <xs:attribute name="onmousedown"/>
-      <xs:attribute name="onmouseup"/>
-      <xs:attribute name="onmouseover"/>
-      <xs:attribute name="onmousemove"/>
-      <xs:attribute name="onmouseout"/>
-      <xs:attribute name="onkeypress"/>
-      <xs:attribute name="onkeydown"/>
-      <xs:attribute name="onkeyup"/>
-      <xs:attribute name="abbr"/>
-      <xs:attribute name="axis"/>
-      <xs:attribute name="headers"/>
-      <xs:attribute name="scope">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="row"/>
-            <xs:enumeration value="col"/>
-            <xs:enumeration value="rowgroup"/>
-            <xs:enumeration value="colgroup"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="rowspan" type="xs:NMTOKEN"/>
-      <xs:attribute name="colspan" type="xs:NMTOKEN"/>
-      <xs:attribute name="align">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="center"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="justify"/>
-            <xs:enumeration value="char"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="char"/>
-      <xs:attribute name="charoff"/>
-      <xs:attribute name="valign">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="top"/>
-            <xs:enumeration value="middle"/>
-            <xs:enumeration value="bottom"/>
-            <xs:enumeration value="baseline"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgset">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:msgentry"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:simplemsgentry"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element maxOccurs="unbounded" ref="docbook:msg"/>
-        <xs:element minOccurs="0" ref="docbook:msginfo"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:msgexplan"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="simplemsgentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element ref="docbook:msgtext"/>
-        <xs:element maxOccurs="unbounded" ref="docbook:msgexplan"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="msgaud"/>
-      <xs:attribute name="msgorig"/>
-      <xs:attribute name="msglevel"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msg">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element ref="docbook:msgmain"/>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:msgsub"/>
-          <xs:element ref="docbook:msgrel"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgmain">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element ref="docbook:msgtext"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgsub">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element ref="docbook:msgtext"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgrel">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element ref="docbook:msgtext"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgtext">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:itemizedlist"/>
-        <xs:element ref="docbook:orderedlist"/>
-        <xs:element ref="docbook:procedure"/>
-        <xs:element ref="docbook:simplelist"/>
-        <xs:element ref="docbook:variablelist"/>
-        <xs:element ref="docbook:segmentedlist"/>
-        <xs:element ref="docbook:glosslist"/>
-        <xs:element ref="docbook:bibliolist"/>
-        <xs:element ref="docbook:calloutlist"/>
-        <xs:element ref="docbook:qandaset"/>
-        <xs:element ref="docbook:example"/>
-        <xs:element ref="docbook:figure"/>
-        <xs:element ref="docbook:table"/>
-        <xs:element ref="docbook:equation"/>
-        <xs:element ref="docbook:informalexample"/>
-        <xs:element ref="docbook:informalfigure"/>
-        <xs:element ref="docbook:informaltable"/>
-        <xs:element ref="docbook:informalequation"/>
-        <xs:element ref="docbook:sidebar"/>
-        <xs:element ref="docbook:blockquote"/>
-        <xs:element ref="docbook:address"/>
-        <xs:element ref="docbook:epigraph"/>
-        <xs:element ref="docbook:mediaobject"/>
-        <xs:element ref="docbook:screenshot"/>
-        <xs:element ref="docbook:task"/>
-        <xs:element ref="docbook:productionset"/>
-        <xs:element ref="docbook:constraintdef"/>
-        <xs:element ref="docbook:msgset"/>
-        <xs:element ref="docbook:screen"/>
-        <xs:element ref="docbook:literallayout"/>
-        <xs:element ref="docbook:programlistingco"/>
-        <xs:element ref="docbook:screenco"/>
-        <xs:element ref="docbook:programlisting"/>
-        <xs:element ref="docbook:synopsis"/>
-        <xs:element ref="docbook:bridgehead"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:revhistory"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:funcsynopsis"/>
-        <xs:element ref="docbook:classsynopsis"/>
-        <xs:element ref="docbook:methodsynopsis"/>
-        <xs:element ref="docbook:constructorsynopsis"/>
-        <xs:element ref="docbook:destructorsynopsis"/>
-        <xs:element ref="docbook:fieldsynopsis"/>
-        <xs:element ref="docbook:cmdsynopsis"/>
-        <xs:element ref="docbook:caution"/>
-        <xs:element ref="docbook:important"/>
-        <xs:element ref="docbook:note"/>
-        <xs:element ref="docbook:tip"/>
-        <xs:element ref="docbook:warning"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:para"/>
-        <xs:element ref="docbook:formalpara"/>
-        <xs:element ref="docbook:simpara"/>
-        <xs:element ref="docbook:annotation"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msginfo">
-    <xs:complexType>
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:msglevel"/>
-        <xs:element ref="docbook:msgorig"/>
-        <xs:element ref="docbook:msgaud"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msglevel">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgorig">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgaud">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="msgexplan">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="qandaset">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:qandadiv"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:qandaentry"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="defaultlabel">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="none"/>
-            <xs:enumeration value="number"/>
-            <xs:enumeration value="qanda"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="qandadiv">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:qandadiv"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:qandaentry"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="qandaentry">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element ref="docbook:question"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:answer"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="question">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:label"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="answer">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:label"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="label">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="equation">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:alt"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:mediaobject"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:mathphrase"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:caption"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="label"/>
-      <xs:attribute name="pgwide">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="0"/>
-            <xs:enumeration value="1"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="floatstyle"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="informalequation">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:element minOccurs="0" ref="docbook:alt"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:mediaobject"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:mathphrase"/>
-        </xs:choice>
-        <xs:element minOccurs="0" ref="docbook:caption"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="inlineequation">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:alt"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:inlinemediaobject"/>
-          <xs:element maxOccurs="unbounded" ref="docbook:mathphrase"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="mathphrase">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:emphasis"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="markup">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tag">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="attribute"/>
-            <xs:enumeration value="attvalue"/>
-            <xs:enumeration value="element"/>
-            <xs:enumeration value="emptytag"/>
-            <xs:enumeration value="endtag"/>
-            <xs:enumeration value="genentity"/>
-            <xs:enumeration value="localname"/>
-            <xs:enumeration value="namespace"/>
-            <xs:enumeration value="numcharref"/>
-            <xs:enumeration value="paramentity"/>
-            <xs:enumeration value="pi"/>
-            <xs:enumeration value="prefix"/>
-            <xs:enumeration value="comment"/>
-            <xs:enumeration value="starttag"/>
-            <xs:enumeration value="xmlpi"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="namespace"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="symbol">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="limit"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="token">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="literal">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="code">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="language"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="constant">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="limit"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="productname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="copyright"/>
-            <xs:enumeration value="registered"/>
-            <xs:enumeration value="service"/>
-            <xs:enumeration value="trade"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="productnumber">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="database">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="altkey"/>
-            <xs:enumeration value="constraint"/>
-            <xs:enumeration value="datatype"/>
-            <xs:enumeration value="field"/>
-            <xs:enumeration value="foreignkey"/>
-            <xs:enumeration value="group"/>
-            <xs:enumeration value="index"/>
-            <xs:enumeration value="key1"/>
-            <xs:enumeration value="key2"/>
-            <xs:enumeration value="name"/>
-            <xs:enumeration value="primarykey"/>
-            <xs:enumeration value="procedure"/>
-            <xs:enumeration value="record"/>
-            <xs:enumeration value="rule"/>
-            <xs:enumeration value="secondarykey"/>
-            <xs:enumeration value="table"/>
-            <xs:enumeration value="user"/>
-            <xs:enumeration value="view"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="application">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="hardware"/>
-            <xs:enumeration value="software"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="hardware">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="guibutton">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:accel"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="guiicon">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:accel"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="guilabel">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:accel"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="guimenu">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:accel"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="guimenuitem">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:accel"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="guisubmenu">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:accel"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="menuchoice">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:shortcut"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:guibutton"/>
-          <xs:element ref="docbook:guiicon"/>
-          <xs:element ref="docbook:guilabel"/>
-          <xs:element ref="docbook:guimenu"/>
-          <xs:element ref="docbook:guimenuitem"/>
-          <xs:element ref="docbook:guisubmenu"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="mousebutton">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="keycap">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="function">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="alt"/>
-            <xs:enumeration value="backspace"/>
-            <xs:enumeration value="command"/>
-            <xs:enumeration value="control"/>
-            <xs:enumeration value="delete"/>
-            <xs:enumeration value="down"/>
-            <xs:enumeration value="end"/>
-            <xs:enumeration value="enter"/>
-            <xs:enumeration value="escape"/>
-            <xs:enumeration value="home"/>
-            <xs:enumeration value="insert"/>
-            <xs:enumeration value="left"/>
-            <xs:enumeration value="meta"/>
-            <xs:enumeration value="option"/>
-            <xs:enumeration value="pagedown"/>
-            <xs:enumeration value="pageup"/>
-            <xs:enumeration value="right"/>
-            <xs:enumeration value="shift"/>
-            <xs:enumeration value="space"/>
-            <xs:enumeration value="tab"/>
-            <xs:enumeration value="up"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otherfunction"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="keycode">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="keycombo">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:mousebutton"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="action">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="click"/>
-            <xs:enumeration value="double-click"/>
-            <xs:enumeration value="press"/>
-            <xs:enumeration value="seq"/>
-            <xs:enumeration value="simul"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otheraction"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="keysym">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="accel">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="shortcut">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:mousebutton"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="action">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="click"/>
-            <xs:enumeration value="double-click"/>
-            <xs:enumeration value="press"/>
-            <xs:enumeration value="seq"/>
-            <xs:enumeration value="simul"/>
-            <xs:enumeration value="other"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="otheraction"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="prompt">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="envar">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="filename">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="path"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="devicefile"/>
-            <xs:enumeration value="directory"/>
-            <xs:enumeration value="extension"/>
-            <xs:enumeration value="headerfile"/>
-            <xs:enumeration value="libraryfile"/>
-            <xs:enumeration value="partition"/>
-            <xs:enumeration value="symlink"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="command">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="computeroutput">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:co"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="userinput">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:co"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="cmdsynopsis">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:command"/>
-          <xs:element ref="docbook:arg"/>
-          <xs:element ref="docbook:group"/>
-          <xs:element ref="docbook:sbr"/>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:synopfragment"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="sepchar"/>
-      <xs:attribute name="cmdlength"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="arg">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:arg"/>
-        <xs:element ref="docbook:group"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:synopfragmentref"/>
-        <xs:element ref="docbook:sbr"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="rep" default="norepeat">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="norepeat"/>
-            <xs:enumeration value="repeat"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="choice" default="opt">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="opt"/>
-            <xs:enumeration value="plain"/>
-            <xs:enumeration value="req"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="group">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:arg"/>
-        <xs:element ref="docbook:group"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:synopfragmentref"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:sbr"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="rep" default="norepeat">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="norepeat"/>
-            <xs:enumeration value="repeat"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="choice" default="opt">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="opt"/>
-            <xs:enumeration value="plain"/>
-            <xs:enumeration value="req"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="sbr">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="synopfragment">
-    <xs:complexType>
-      <xs:choice maxOccurs="unbounded">
-        <xs:element ref="docbook:arg"/>
-        <xs:element ref="docbook:group"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="synopfragmentref">
-    <xs:complexType mixed="true">
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="synopsis">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:textobject"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:lineannotation"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="linenumbering">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="numbered"/>
-            <xs:enumeration value="unnumbered"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startinglinenumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="language"/>
-      <xs:attribute ref="xml:space"/>
-      <xs:attribute name="label"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="funcsynopsis">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" ref="docbook:info"/>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:funcsynopsisinfo"/>
-          <xs:element ref="docbook:funcprototype"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="language"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="funcsynopsisinfo">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:textobject"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:lineannotation"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="linenumbering">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="numbered"/>
-            <xs:enumeration value="unnumbered"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startinglinenumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="language"/>
-      <xs:attribute ref="xml:space"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="funcprototype">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-        <xs:element ref="docbook:funcdef"/>
-        <xs:choice>
-          <xs:element ref="docbook:void"/>
-          <xs:element ref="docbook:varargs"/>
-          <xs:sequence>
-            <xs:element maxOccurs="unbounded" ref="docbook:paramdef"/>
-            <xs:element minOccurs="0" ref="docbook:varargs"/>
-          </xs:sequence>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="funcdef">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:function"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="function">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="void">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="varargs">
-    <xs:complexType>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="paramdef">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:funcparams"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="choice" default="opt">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="opt"/>
-            <xs:enumeration value="req"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="funcparams">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="classsynopsis">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:ooclass"/>
-          <xs:element ref="docbook:ooexception"/>
-          <xs:element ref="docbook:oointerface"/>
-        </xs:choice>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:classsynopsisinfo"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="language"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="class"/>
-            <xs:enumeration value="interface"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="classsynopsisinfo">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:textobject"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:lineannotation"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="linenumbering">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="numbered"/>
-            <xs:enumeration value="unnumbered"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startinglinenumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="language"/>
-      <xs:attribute ref="xml:space"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="ooclass">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:package"/>
-          <xs:element ref="docbook:modifier"/>
-        </xs:choice>
-        <xs:element ref="docbook:classname"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="oointerface">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:package"/>
-          <xs:element ref="docbook:modifier"/>
-        </xs:choice>
-        <xs:element ref="docbook:interfacename"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="ooexception">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:package"/>
-          <xs:element ref="docbook:modifier"/>
-        </xs:choice>
-        <xs:element ref="docbook:exceptionname"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="modifier">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute ref="xml:space"/>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="interfacename">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="exceptionname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="fieldsynopsis">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-        <xs:element minOccurs="0" ref="docbook:type"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element minOccurs="0" ref="docbook:initializer"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="language"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="initializer">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="constructorsynopsis">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-        <xs:element minOccurs="0" ref="docbook:methodname"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:methodparam"/>
-          <xs:element minOccurs="0" ref="docbook:void"/>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:exceptionname"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="language"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="destructorsynopsis">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-        <xs:element minOccurs="0" ref="docbook:methodname"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:methodparam"/>
-          <xs:element minOccurs="0" ref="docbook:void"/>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:exceptionname"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="language"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="methodsynopsis">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-        <xs:choice minOccurs="0">
-          <xs:element ref="docbook:type"/>
-          <xs:element ref="docbook:void"/>
-        </xs:choice>
-        <xs:element ref="docbook:methodname"/>
-        <xs:choice>
-          <xs:element maxOccurs="unbounded" ref="docbook:methodparam"/>
-          <xs:element ref="docbook:void"/>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:exceptionname"/>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="language"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="methodname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="methodparam">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-          <xs:element ref="docbook:modifier"/>
-          <xs:element ref="docbook:type"/>
-        </xs:choice>
-        <xs:choice>
-          <xs:sequence>
-            <xs:element ref="docbook:parameter"/>
-            <xs:element minOccurs="0" ref="docbook:initializer"/>
-          </xs:sequence>
-          <xs:element ref="docbook:funcparams"/>
-        </xs:choice>
-        <xs:element minOccurs="0" maxOccurs="unbounded" ref="docbook:modifier"/>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="rep" default="norepeat">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="norepeat"/>
-            <xs:enumeration value="repeat"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="choice" default="req">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="opt"/>
-            <xs:enumeration value="plain"/>
-            <xs:enumeration value="req"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="varname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="returnvalue">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="type">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="classname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="programlisting">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:info"/>
-        <xs:element ref="docbook:textobject"/>
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:abbrev"/>
-        <xs:element ref="docbook:acronym"/>
-        <xs:element ref="docbook:date"/>
-        <xs:element ref="docbook:emphasis"/>
-        <xs:element ref="docbook:footnote"/>
-        <xs:element ref="docbook:footnoteref"/>
-        <xs:element ref="docbook:foreignphrase"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:quote"/>
-        <xs:element ref="docbook:wordasword"/>
-        <xs:element ref="docbook:firstterm"/>
-        <xs:element ref="docbook:glossterm"/>
-        <xs:element ref="docbook:coref"/>
-        <xs:element ref="docbook:trademark"/>
-        <xs:element ref="docbook:productnumber"/>
-        <xs:element ref="docbook:productname"/>
-        <xs:element ref="docbook:database"/>
-        <xs:element ref="docbook:application"/>
-        <xs:element ref="docbook:hardware"/>
-        <xs:element ref="docbook:citation"/>
-        <xs:element ref="docbook:citerefentry"/>
-        <xs:element ref="docbook:citetitle"/>
-        <xs:element ref="docbook:citebiblioid"/>
-        <xs:element ref="docbook:author"/>
-        <xs:element ref="docbook:person"/>
-        <xs:element ref="docbook:personname"/>
-        <xs:element ref="docbook:org"/>
-        <xs:element ref="docbook:orgname"/>
-        <xs:element ref="docbook:editor"/>
-        <xs:element ref="docbook:jobtitle"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:package"/>
-        <xs:element ref="docbook:parameter"/>
-        <xs:element ref="docbook:termdef"/>
-        <xs:element ref="docbook:nonterminal"/>
-        <xs:element ref="docbook:systemitem"/>
-        <xs:element ref="docbook:option"/>
-        <xs:element ref="docbook:optional"/>
-        <xs:element ref="docbook:property"/>
-        <xs:element ref="docbook:inlineequation"/>
-        <xs:element ref="docbook:tag"/>
-        <xs:element ref="docbook:markup"/>
-        <xs:element ref="docbook:token"/>
-        <xs:element ref="docbook:symbol"/>
-        <xs:element ref="docbook:literal"/>
-        <xs:element ref="docbook:code"/>
-        <xs:element ref="docbook:constant"/>
-        <xs:element ref="docbook:email"/>
-        <xs:element ref="docbook:uri"/>
-        <xs:element ref="docbook:guiicon"/>
-        <xs:element ref="docbook:guibutton"/>
-        <xs:element ref="docbook:guimenuitem"/>
-        <xs:element ref="docbook:guimenu"/>
-        <xs:element ref="docbook:guisubmenu"/>
-        <xs:element ref="docbook:guilabel"/>
-        <xs:element ref="docbook:menuchoice"/>
-        <xs:element ref="docbook:mousebutton"/>
-        <xs:element ref="docbook:keycombo"/>
-        <xs:element ref="docbook:keycap"/>
-        <xs:element ref="docbook:keycode"/>
-        <xs:element ref="docbook:keysym"/>
-        <xs:element ref="docbook:shortcut"/>
-        <xs:element ref="docbook:accel"/>
-        <xs:element ref="docbook:prompt"/>
-        <xs:element ref="docbook:envar"/>
-        <xs:element ref="docbook:filename"/>
-        <xs:element ref="docbook:command"/>
-        <xs:element ref="docbook:computeroutput"/>
-        <xs:element ref="docbook:userinput"/>
-        <xs:element ref="docbook:function"/>
-        <xs:element ref="docbook:varname"/>
-        <xs:element ref="docbook:returnvalue"/>
-        <xs:element ref="docbook:type"/>
-        <xs:element ref="docbook:classname"/>
-        <xs:element ref="docbook:exceptionname"/>
-        <xs:element ref="docbook:interfacename"/>
-        <xs:element ref="docbook:methodname"/>
-        <xs:element ref="docbook:modifier"/>
-        <xs:element ref="docbook:initializer"/>
-        <xs:element ref="docbook:ooclass"/>
-        <xs:element ref="docbook:ooexception"/>
-        <xs:element ref="docbook:oointerface"/>
-        <xs:element ref="docbook:errorcode"/>
-        <xs:element ref="docbook:errortext"/>
-        <xs:element ref="docbook:errorname"/>
-        <xs:element ref="docbook:errortype"/>
-        <xs:element ref="docbook:lineannotation"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="continuation">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="continues"/>
-            <xs:enumeration value="restarts"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="linenumbering">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="numbered"/>
-            <xs:enumeration value="unnumbered"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-      <xs:attribute name="startinglinenumber" type="xs:NMTOKEN"/>
-      <xs:attribute name="language"/>
-      <xs:attribute ref="xml:space"/>
-      <xs:attribute name="width" type="xs:NMTOKEN"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="caution">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="important">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="note">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="tip">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="warning">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:sequence>
-          <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element ref="docbook:title"/>
-            <xs:element ref="docbook:titleabbrev"/>
-          </xs:choice>
-          <xs:element minOccurs="0" ref="docbook:info"/>
-        </xs:sequence>
-        <xs:choice maxOccurs="unbounded">
-          <xs:element ref="docbook:itemizedlist"/>
-          <xs:element ref="docbook:orderedlist"/>
-          <xs:element ref="docbook:procedure"/>
-          <xs:element ref="docbook:simplelist"/>
-          <xs:element ref="docbook:variablelist"/>
-          <xs:element ref="docbook:segmentedlist"/>
-          <xs:element ref="docbook:glosslist"/>
-          <xs:element ref="docbook:bibliolist"/>
-          <xs:element ref="docbook:calloutlist"/>
-          <xs:element ref="docbook:qandaset"/>
-          <xs:element ref="docbook:example"/>
-          <xs:element ref="docbook:figure"/>
-          <xs:element ref="docbook:table"/>
-          <xs:element ref="docbook:equation"/>
-          <xs:element ref="docbook:informalexample"/>
-          <xs:element ref="docbook:informalfigure"/>
-          <xs:element ref="docbook:informaltable"/>
-          <xs:element ref="docbook:informalequation"/>
-          <xs:element ref="docbook:sidebar"/>
-          <xs:element ref="docbook:blockquote"/>
-          <xs:element ref="docbook:address"/>
-          <xs:element ref="docbook:epigraph"/>
-          <xs:element ref="docbook:mediaobject"/>
-          <xs:element ref="docbook:screenshot"/>
-          <xs:element ref="docbook:task"/>
-          <xs:element ref="docbook:productionset"/>
-          <xs:element ref="docbook:constraintdef"/>
-          <xs:element ref="docbook:msgset"/>
-          <xs:element ref="docbook:screen"/>
-          <xs:element ref="docbook:literallayout"/>
-          <xs:element ref="docbook:programlistingco"/>
-          <xs:element ref="docbook:screenco"/>
-          <xs:element ref="docbook:programlisting"/>
-          <xs:element ref="docbook:synopsis"/>
-          <xs:element ref="docbook:bridgehead"/>
-          <xs:element ref="docbook:remark"/>
-          <xs:element ref="docbook:revhistory"/>
-          <xs:element ref="docbook:indexterm"/>
-          <xs:element ref="docbook:funcsynopsis"/>
-          <xs:element ref="docbook:classsynopsis"/>
-          <xs:element ref="docbook:methodsynopsis"/>
-          <xs:element ref="docbook:constructorsynopsis"/>
-          <xs:element ref="docbook:destructorsynopsis"/>
-          <xs:element ref="docbook:fieldsynopsis"/>
-          <xs:element ref="docbook:cmdsynopsis"/>
-          <xs:element ref="docbook:caution"/>
-          <xs:element ref="docbook:important"/>
-          <xs:element ref="docbook:note"/>
-          <xs:element ref="docbook:tip"/>
-          <xs:element ref="docbook:warning"/>
-          <xs:element ref="docbook:anchor"/>
-          <xs:element ref="docbook:para"/>
-          <xs:element ref="docbook:formalpara"/>
-          <xs:element ref="docbook:simpara"/>
-          <xs:element ref="docbook:annotation"/>
-        </xs:choice>
-      </xs:sequence>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="errorcode">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="errorname">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="errortext">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="errortype">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="systemitem">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-        <xs:element ref="docbook:co"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-      <xs:attribute name="class">
-        <xs:simpleType>
-          <xs:restriction base="xs:token">
-            <xs:enumeration value="daemon"/>
-            <xs:enumeration value="domainname"/>
-            <xs:enumeration value="etheraddress"/>
-            <xs:enumeration value="event"/>
-            <xs:enumeration value="eventhandler"/>
-            <xs:enumeration value="filesystem"/>
-            <xs:enumeration value="fqdomainname"/>
-            <xs:enumeration value="groupname"/>
-            <xs:enumeration value="ipaddress"/>
-            <xs:enumeration value="library"/>
-            <xs:enumeration value="macro"/>
-            <xs:enumeration value="netmask"/>
-            <xs:enumeration value="newsgroup"/>
-            <xs:enumeration value="osname"/>
-            <xs:enumeration value="process"/>
-            <xs:enumeration value="protocol"/>
-            <xs:enumeration value="resource"/>
-            <xs:enumeration value="server"/>
-            <xs:enumeration value="service"/>
-            <xs:enumeration value="systemname"/>
-            <xs:enumeration value="username"/>
-          </xs:restriction>
-        </xs:simpleType>
-      </xs:attribute>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="option">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="optional">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-  <xs:element name="property">
-    <xs:complexType mixed="true">
-      <xs:choice minOccurs="0" maxOccurs="unbounded">
-        <xs:element ref="docbook:inlinemediaobject"/>
-        <xs:element ref="docbook:remark"/>
-        <xs:element ref="docbook:superscript"/>
-        <xs:element ref="docbook:subscript"/>
-        <xs:element ref="docbook:xref"/>
-        <xs:element ref="docbook:link"/>
-        <xs:element ref="docbook:olink"/>
-        <xs:element ref="docbook:anchor"/>
-        <xs:element ref="docbook:biblioref"/>
-        <xs:element ref="docbook:alt"/>
-        <xs:element ref="docbook:annotation"/>
-        <xs:element ref="docbook:indexterm"/>
-        <xs:element ref="docbook:phrase"/>
-        <xs:element ref="docbook:replaceable"/>
-      </xs:choice>
-      <xs:attribute name="role"/>
-      <xs:attributeGroup ref="docbook:db.common.attributes"/>
-      <xs:attributeGroup ref="docbook:db.common.linking.attributes"/>
-    </xs:complexType>
-  </xs:element>
-</xs:schema>
index e9ce6355ac4bda6f578300fccdbe0dd46cfadf9e..199a469bd69aa54a29f6cdf959caa2d45a155575 100644 (file)
-<?xml version='1.0' encoding='UTF-8'?>\r
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink">\r
\r
- <xs:annotation>\r
-  <xs:documentation>This schema is not normative, or even definitive.  The\r
-prose copy in the XLink 1.1 recommendation (http://www.w3.org/TR/xlink11/) is\r
-definitive, although it should not differ from this file, except for the\r
-absence of these two initial comments.</xs:documentation>\r
- </xs:annotation>\r
\r
- <xs:annotation>\r
-  <xs:documentation>In keeping with the W3C's standard versioning\r
-   policy, this schema document will persist at\r
-   http://www.w3.org/XML/2008/06/xlink.xsd.\r
-   At the date of issue it can also be found at\r
-   http://www.w3.org/1999/xlink.xsd.\r
-   The schema document at that URI may however change in the future,\r
-   in order to remain compatible with the latest version of XML Schema\r
-   itself, or with the XLink namespace itself.  In other words, if the XML\r
-   Schema or XLink namespaces change, the version of this document at\r
-   http://www.w3.org/1999/xlink.xsd will change\r
-   accordingly; the version at\r
-   http://www.w3.org/2008/06/xlink.xsd will not change.\r
-</xs:documentation>\r
- </xs:annotation>\r
\r
- <xs:annotation>\r
-  <xs:documentation>This schema document provides attribute declarations and\r
-attribute group, complex type and simple type definitions which can be used in\r
-the construction of user schemas to define the structure of particular linking\r
-constructs, e.g.\r
-<![CDATA[\r
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"\r
-           xmlns:xl="http://www.w3.org/1999/xlink">\r
-\r
- <xs:import namespace="http://www.w3.org/1999/xlink"\r
-            location="http://www.w3.org/1999/xlink.xsd">\r
-\r
- <xs:element name="mySimple">\r
-  <xs:complexType>\r
-   ...\r
-   <xs:attributeGroup ref="xl:simpleAttrs"/>\r
-   ...\r
-  </xs:complexType>\r
- </xs:element>\r
- ...\r
-</xs:schema>]]></xs:documentation>\r
- </xs:annotation>\r
-\r
- <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>\r
-\r
- <xs:attribute name="type" type="xlink:typeType"/>\r
-\r
- <xs:simpleType name="typeType">\r
-  <xs:restriction base="xs:token">\r
-   <xs:enumeration value="simple"/>\r
-   <xs:enumeration value="extended"/>\r
-   <xs:enumeration value="title"/>\r
-   <xs:enumeration value="resource"/>\r
-   <xs:enumeration value="locator"/>\r
-   <xs:enumeration value="arc"/>\r
-  </xs:restriction>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="href" type="xlink:hrefType"/>\r
-\r
- <xs:simpleType name="hrefType">\r
-  <xs:restriction base="xs:anyURI"/>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="role" type="xlink:roleType"/>\r
-\r
- <xs:simpleType name="roleType">\r
-  <xs:restriction base="xs:anyURI">\r
-   <xs:minLength value="1"/>\r
-  </xs:restriction>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="arcrole" type="xlink:arcroleType"/>\r
-\r
- <xs:simpleType name="arcroleType">\r
-  <xs:restriction base="xs:anyURI">\r
-   <xs:minLength value="1"/>\r
-  </xs:restriction>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="title" type="xlink:titleAttrType"/>\r
-\r
- <xs:simpleType name="titleAttrType">\r
-  <xs:restriction base="xs:string"/>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="show" type="xlink:showType"/>\r
-\r
- <xs:simpleType name="showType">\r
-  <xs:restriction base="xs:token">\r
-   <xs:enumeration value="new"/>\r
-   <xs:enumeration value="replace"/>\r
-   <xs:enumeration value="embed"/>\r
-   <xs:enumeration value="other"/>\r
-   <xs:enumeration value="none"/>\r
-  </xs:restriction>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="actuate" type="xlink:actuateType"/>\r
-\r
- <xs:simpleType name="actuateType">\r
-  <xs:restriction base="xs:token">\r
-   <xs:enumeration value="onLoad"/>\r
-   <xs:enumeration value="onRequest"/>\r
-   <xs:enumeration value="other"/>\r
-   <xs:enumeration value="none"/>\r
-  </xs:restriction>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="label" type="xlink:labelType"/>\r
-\r
- <xs:simpleType name="labelType">\r
-  <xs:restriction base="xs:NCName"/>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="from" type="xlink:fromType"/>\r
-\r
- <xs:simpleType name="fromType">\r
-  <xs:restriction base="xs:NCName"/>\r
- </xs:simpleType>\r
-\r
- <xs:attribute name="to" type="xlink:toType"/>\r
-\r
- <xs:simpleType name="toType">\r
-  <xs:restriction base="xs:NCName"/>\r
- </xs:simpleType>\r
-\r
- <xs:attributeGroup name="simpleAttrs">\r
-  <xs:attribute ref="xlink:type" fixed="simple"/>\r
-  <xs:attribute ref="xlink:href"/>\r
-  <xs:attribute ref="xlink:role"/>\r
-  <xs:attribute ref="xlink:arcrole"/>\r
-  <xs:attribute ref="xlink:title"/>\r
-  <xs:attribute ref="xlink:show"/>\r
-  <xs:attribute ref="xlink:actuate"/>\r
- </xs:attributeGroup>\r
-\r
- <xs:group name="simpleModel">\r
-  <xs:sequence>\r
-   <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
-  </xs:sequence>\r
- </xs:group>\r
-\r
- <xs:complexType mixed="true" name="simple">\r
-  <xs:annotation>\r
-   <xs:documentation>\r
-    Intended for use as the type of user-declared elements to make them\r
-    simple links.\r
-   </xs:documentation>\r
-  </xs:annotation>\r
-  <xs:group ref="xlink:simpleModel"/>\r
-  <xs:attributeGroup ref="xlink:simpleAttrs"/>\r
- </xs:complexType>\r
-\r
- <xs:attributeGroup name="extendedAttrs">\r
-  <xs:attribute ref="xlink:type" fixed="extended" use="required"/>\r
-  <xs:attribute ref="xlink:role"/>\r
-  <xs:attribute ref="xlink:title"/>\r
- </xs:attributeGroup>\r
-\r
- <xs:group name="extendedModel">\r
-   <xs:choice>\r
-    <xs:element ref="xlink:title"/>\r
-    <xs:element ref="xlink:resource"/>\r
-    <xs:element ref="xlink:locator"/>\r
-    <xs:element ref="xlink:arc"/>\r
-  </xs:choice>\r
- </xs:group>\r
-\r
- <xs:complexType name="extended">\r
-  <xs:annotation>\r
-   <xs:documentation>\r
-    Intended for use as the type of user-declared elements to make them\r
-    extended links.\r
-    Note that the elements referenced in the content model are all abstract.\r
-    The intention is that by simply declaring elements with these as their\r
-    substitutionGroup, all the right things will happen.\r
-   </xs:documentation>\r
-  </xs:annotation>\r
-  <xs:group ref="xlink:extendedModel" minOccurs="0" maxOccurs="unbounded"/>\r
-  <xs:attributeGroup ref="xlink:extendedAttrs"/>\r
- </xs:complexType>\r
-\r
- <xs:element name="title" type="xlink:titleEltType" abstract="true"/>\r
-\r
- <xs:attributeGroup name="titleAttrs">\r
-  <xs:attribute ref="xlink:type" fixed="title" use="required"/>\r
-  <xs:attribute ref="xml:lang">\r
-   <xs:annotation>\r
-    <xs:documentation>\r
-     xml:lang is not required, but provides much of the\r
-     motivation for title elements in addition to attributes, and so\r
-     is provided here for convenience.\r
-    </xs:documentation>\r
-   </xs:annotation>\r
-  </xs:attribute>\r
- </xs:attributeGroup>\r
-\r
- <xs:group name="titleModel">\r
-  <xs:sequence>\r
-   <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
-  </xs:sequence>\r
- </xs:group>\r
-\r
- <xs:complexType mixed="true" name="titleEltType">\r
-  <xs:group ref="xlink:titleModel"/>\r
-  <xs:attributeGroup ref="xlink:titleAttrs"/>\r
- </xs:complexType>\r
-\r
- <xs:element name="resource" type="xlink:resourceType" abstract="true"/>\r
-\r
- <xs:attributeGroup name="resourceAttrs">\r
-  <xs:attribute ref="xlink:type" fixed="resource" use="required"/>\r
-  <xs:attribute ref="xlink:role"/>\r
-  <xs:attribute ref="xlink:title"/>\r
-  <xs:attribute ref="xlink:label"/>\r
- </xs:attributeGroup>\r
-\r
- <xs:group name="resourceModel">\r
-  <xs:sequence>\r
-   <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>\r
-  </xs:sequence>\r
- </xs:group>\r
-\r
- <xs:complexType mixed="true" name="resourceType">\r
-  <xs:group ref="xlink:resourceModel"/>\r
-  <xs:attributeGroup ref="xlink:resourceAttrs"/>\r
- </xs:complexType>\r
-\r
- <xs:element name="locator" type="xlink:locatorType" abstract="true"/>\r
-\r
- <xs:attributeGroup name="locatorAttrs">\r
-  <xs:attribute ref="xlink:type" fixed="locator" use="required"/>\r
-  <xs:attribute ref="xlink:href" use="required"/>\r
-  <xs:attribute ref="xlink:role"/>\r
-  <xs:attribute ref="xlink:title"/>\r
-  <xs:attribute ref="xlink:label">\r
-   <xs:annotation>\r
-    <xs:documentation>\r
-     label is not required, but locators have no particular\r
-     XLink function if they are not labeled.\r
-    </xs:documentation>\r
-   </xs:annotation>\r
-  </xs:attribute>\r
- </xs:attributeGroup>\r
-\r
- <xs:group name="locatorModel">\r
-  <xs:sequence>\r
-   <xs:element ref="xlink:title" minOccurs="0" maxOccurs="unbounded"/>\r
-  </xs:sequence>\r
- </xs:group>\r
-\r
- <xs:complexType name="locatorType">\r
-  <xs:group ref="xlink:locatorModel"/>\r
-  <xs:attributeGroup ref="xlink:locatorAttrs"/>\r
- </xs:complexType>\r
-\r
- <xs:element name="arc" type="xlink:arcType" abstract="true"/>\r
-\r
- <xs:attributeGroup name="arcAttrs">\r
-  <xs:attribute ref="xlink:type" fixed="arc" use="required"/>\r
-  <xs:attribute ref="xlink:arcrole"/>\r
-  <xs:attribute ref="xlink:title"/>\r
-  <xs:attribute ref="xlink:show"/>\r
-  <xs:attribute ref="xlink:actuate"/>\r
-  <xs:attribute ref="xlink:from"/>\r
-  <xs:attribute ref="xlink:to">\r
-   <xs:annotation>\r
-    <xs:documentation>\r
-     from and to have default behavior when values are missing\r
-    </xs:documentation>\r
-   </xs:annotation>\r
-  </xs:attribute>\r
- </xs:attributeGroup>\r
-\r
- <xs:group name="arcModel">\r
-  <xs:sequence>\r
-   <xs:element ref="xlink:title" minOccurs="0" maxOccurs="unbounded"/>\r
-  </xs:sequence>\r
- </xs:group>\r
-\r
- <xs:complexType name="arcType">\r
-  <xs:group ref="xlink:arcModel"/>\r
-  <xs:attributeGroup ref="xlink:arcAttrs"/>\r
- </xs:complexType>\r
-\r
-</xs:schema>\r
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <xs:annotation>
+  <xs:documentation>This schema document provides attribute declarations and
+attribute group, complex type and simple type definitions which can be used in
+the construction of user schemas to define the structure of particular linking
+constructs, e.g.
+<![CDATA[
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns:xl="http://www.w3.org/1999/xlink">
+
+ <xs:import namespace="http://www.w3.org/1999/xlink"
+            location="http://www.w3.org/1999/xlink.xsd">
+
+ <xs:element name="mySimple">
+  <xs:complexType>
+   ...
+   <xs:attributeGroup ref="xl:simpleAttrs"/>
+   ...
+  </xs:complexType>
+ </xs:element>
+ ...
+</xs:schema>]]></xs:documentation>
+ </xs:annotation>
+
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+
+ <xs:attribute name="type" type="xlink:typeType"/>
+
+ <xs:simpleType name="typeType">
+  <xs:restriction base="xs:token">
+   <xs:enumeration value="simple"/>
+   <xs:enumeration value="extended"/>
+   <xs:enumeration value="title"/>
+   <xs:enumeration value="resource"/>
+   <xs:enumeration value="locator"/>
+   <xs:enumeration value="arc"/>
+  </xs:restriction>
+ </xs:simpleType>
+
+ <xs:attribute name="href" type="xlink:hrefType"/>
+
+ <xs:simpleType name="hrefType">
+  <xs:restriction base="xs:anyURI"/>
+ </xs:simpleType>
+
+ <xs:attribute name="role" type="xlink:roleType"/>
+
+ <xs:simpleType name="roleType">
+  <xs:restriction base="xs:anyURI">
+   <xs:minLength value="1"/>
+  </xs:restriction>
+ </xs:simpleType>
+
+ <xs:attribute name="arcrole" type="xlink:arcroleType"/>
+
+ <xs:simpleType name="arcroleType">
+  <xs:restriction base="xs:anyURI">
+   <xs:minLength value="1"/>
+  </xs:restriction>
+ </xs:simpleType>
+
+ <xs:attribute name="title" type="xlink:titleAttrType"/>
+
+ <xs:simpleType name="titleAttrType">
+  <xs:restriction base="xs:string"/>
+ </xs:simpleType>
+
+ <xs:attribute name="show" type="xlink:showType"/>
+
+ <xs:simpleType name="showType">
+  <xs:restriction base="xs:token">
+   <xs:enumeration value="new"/>
+   <xs:enumeration value="replace"/>
+   <xs:enumeration value="embed"/>
+   <xs:enumeration value="other"/>
+   <xs:enumeration value="none"/>
+  </xs:restriction>
+ </xs:simpleType>
+
+ <xs:attribute name="actuate" type="xlink:actuateType"/>
+
+ <xs:simpleType name="actuateType">
+  <xs:restriction base="xs:token">
+   <xs:enumeration value="onLoad"/>
+   <xs:enumeration value="onRequest"/>
+   <xs:enumeration value="other"/>
+   <xs:enumeration value="none"/>
+  </xs:restriction>
+ </xs:simpleType>
+
+ <xs:attribute name="label" type="xlink:labelType"/>
+
+ <xs:simpleType name="labelType">
+  <xs:restriction base="xs:NCName"/>
+ </xs:simpleType>
+
+ <xs:attribute name="from" type="xlink:fromType"/>
+
+ <xs:simpleType name="fromType">
+  <xs:restriction base="xs:NCName"/>
+ </xs:simpleType>
+
+ <xs:attribute name="to" type="xlink:toType"/>
+
+ <xs:simpleType name="toType">
+  <xs:restriction base="xs:NCName"/>
+ </xs:simpleType>
+
+ <xs:attributeGroup name="simpleAttrs">
+  <xs:attribute ref="xlink:type" fixed="simple"/>
+  <xs:attribute ref="xlink:href"/>
+  <xs:attribute ref="xlink:role"/>
+  <xs:attribute ref="xlink:arcrole"/>
+  <xs:attribute ref="xlink:title"/>
+  <xs:attribute ref="xlink:show"/>
+  <xs:attribute ref="xlink:actuate"/>
+ </xs:attributeGroup>
+
+ <xs:group name="simpleModel">
+  <xs:sequence>
+   <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+  </xs:sequence>
+ </xs:group>
+
+ <xs:complexType mixed="true" name="simple">
+  <xs:annotation>
+   <xs:documentation>
+    Intended for use as the type of user-declared elements to make them
+    simple links.
+   </xs:documentation>
+  </xs:annotation>
+  <xs:group ref="xlink:simpleModel"/>
+  <xs:attributeGroup ref="xlink:simpleAttrs"/>
+ </xs:complexType>
+
+ <xs:attributeGroup name="extendedAttrs">
+  <xs:attribute ref="xlink:type" fixed="extended" use="required"/>
+  <xs:attribute ref="xlink:role"/>
+  <xs:attribute ref="xlink:title"/>
+ </xs:attributeGroup>
+
+ <xs:group name="extendedModel">
+   <xs:choice>
+    <xs:element ref="xlink:title"/>
+    <xs:element ref="xlink:resource"/>
+    <xs:element ref="xlink:locator"/>
+    <xs:element ref="xlink:arc"/>
+  </xs:choice>
+ </xs:group>
+
+ <xs:complexType name="extended">
+  <xs:annotation>
+   <xs:documentation>
+    Intended for use as the type of user-declared elements to make them
+    extended links.
+    Note that the elements referenced in the content model are all abstract.
+    The intention is that by simply declaring elements with these as their
+    substitutionGroup, all the right things will happen.
+   </xs:documentation>
+  </xs:annotation>
+  <xs:group ref="xlink:extendedModel" minOccurs="0" maxOccurs="unbounded"/>
+  <xs:attributeGroup ref="xlink:extendedAttrs"/>
+ </xs:complexType>
+
+ <xs:element name="title" type="xlink:titleEltType" abstract="true"/>
+
+ <xs:attributeGroup name="titleAttrs">
+  <xs:attribute ref="xlink:type" fixed="title" use="required"/>
+  <xs:attribute ref="xml:lang">
+   <xs:annotation>
+    <xs:documentation>
+     xml:lang is not required, but provides much of the
+     motivation for title elements in addition to attributes, and so
+     is provided here for convenience.
+    </xs:documentation>
+   </xs:annotation>
+  </xs:attribute>
+ </xs:attributeGroup>
+
+ <xs:group name="titleModel">
+  <xs:sequence>
+   <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+  </xs:sequence>
+ </xs:group>
+
+ <xs:complexType mixed="true" name="titleEltType">
+  <xs:group ref="xlink:titleModel"/>
+  <xs:attributeGroup ref="xlink:titleAttrs"/>
+ </xs:complexType>
+
+ <xs:element name="resource" type="xlink:resourceType" abstract="true"/>
+
+ <xs:attributeGroup name="resourceAttrs">
+  <xs:attribute ref="xlink:type" fixed="resource" use="required"/>
+  <xs:attribute ref="xlink:role"/>
+  <xs:attribute ref="xlink:title"/>
+  <xs:attribute ref="xlink:label"/>
+ </xs:attributeGroup>
+
+ <xs:group name="resourceModel">
+  <xs:sequence>
+   <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+  </xs:sequence>
+ </xs:group>
+
+ <xs:complexType mixed="true" name="resourceType">
+  <xs:group ref="xlink:resourceModel"/>
+  <xs:attributeGroup ref="xlink:resourceAttrs"/>
+ </xs:complexType>
+
+ <xs:element name="locator" type="xlink:locatorType" abstract="true"/>
+
+ <xs:attributeGroup name="locatorAttrs">
+  <xs:attribute ref="xlink:type" fixed="locator" use="required"/>
+  <xs:attribute ref="xlink:href" use="required"/>
+  <xs:attribute ref="xlink:role"/>
+  <xs:attribute ref="xlink:title"/>
+  <xs:attribute ref="xlink:label">
+   <xs:annotation>
+    <xs:documentation>
+     label is not required, but locators have no particular
+     XLink function if they are not labeled.
+    </xs:documentation>
+   </xs:annotation>
+  </xs:attribute>
+ </xs:attributeGroup>
+
+ <xs:group name="locatorModel">
+  <xs:sequence>
+   <xs:element ref="xlink:title" minOccurs="0" maxOccurs="unbounded"/>
+  </xs:sequence>
+ </xs:group>
+
+ <xs:complexType name="locatorType">
+  <xs:group ref="xlink:locatorModel"/>
+  <xs:attributeGroup ref="xlink:locatorAttrs"/>
+ </xs:complexType>
+
+ <xs:element name="arc" type="xlink:arcType" abstract="true"/>
+
+ <xs:attributeGroup name="arcAttrs">
+  <xs:attribute ref="xlink:type" fixed="arc" use="required"/>
+  <xs:attribute ref="xlink:arcrole"/>
+  <xs:attribute ref="xlink:title"/>
+  <xs:attribute ref="xlink:show"/>
+  <xs:attribute ref="xlink:actuate"/>
+  <xs:attribute ref="xlink:from"/>
+  <xs:attribute ref="xlink:to">
+   <xs:annotation>
+    <xs:documentation>
+     from and to have default behavior when values are missing
+    </xs:documentation>
+   </xs:annotation>
+  </xs:attribute>
+ </xs:attributeGroup>
+
+ <xs:group name="arcModel">
+  <xs:sequence>
+   <xs:element ref="xlink:title" minOccurs="0" maxOccurs="unbounded"/>
+  </xs:sequence>
+ </xs:group>
+
+ <xs:complexType name="arcType">
+  <xs:group ref="xlink:arcModel"/>
+  <xs:attributeGroup ref="xlink:arcAttrs"/>
+ </xs:complexType>
+
+ <!-- Hack required for GML support -->
+ <xs:attributeGroup name="simpleLink">
+  <xs:attribute name="type" type="xs:string" use="optional" fixed="simple" form="qualified"/>
+  <xs:attribute ref="xlink:href" use="optional"/>
+  <xs:attribute ref="xlink:role" use="optional"/>
+  <xs:attribute ref="xlink:arcrole" use="optional"/>
+  <xs:attribute ref="xlink:title" use="optional"/>
+  <xs:attribute ref="xlink:show" use="optional"/>
+  <xs:attribute ref="xlink:actuate" use="optional"/>
+ </xs:attributeGroup>
+</xs:schema>
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/acr/schemas/xml-events-attribs-1.xsd b/org.argeo.cms/src/org/argeo/cms/acr/schemas/xml-events-attribs-1.xsd
deleted file mode 100644 (file)
index ef99128..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema 
-    targetNamespace="http://www.w3.org/2001/xml-events" 
-    xmlns:ev="http://www.w3.org/2001/xml-events" 
-    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-    xsi:schemaLocation="http://www.w3.org/2001/XMLSchema 
-                        http://www.w3.org/2001/XMLSchema.xsd" 
-    elementFormDefault="unqualified" 
-    blockDefault="#all" 
-    finalDefault="#all" 
-    attributeFormDefault="unqualified">
-
-  <xs:annotation>
-    <xs:documentation>
-      This is the XML Schema for XML Events global attributes
-
-      URI: http://www.w3.org/MarkUp/SCHEMA/xml-events-attribs-1.xsd
-      $Id: xml-events-attribs-1.xsd,v 1.7 2004/11/22 17:09:15 ahby Exp $
-    </xs:documentation>
-    <xs:documentation source="xml-events-copyright-1.xsd"/>
-  </xs:annotation>
-
-  <xs:annotation>
-    <xs:documentation>
-      XML Event Attributes
-               
-        These "global" event attributes are defined in "Attaching
-        Attributes Directly to the Observer Element" of the XML
-        Events specification.
-    </xs:documentation>
-  </xs:annotation>
-
-  <xs:attribute name="event" type="xs:NMTOKEN"/>
-  <xs:attribute name="observer" type="xs:IDREF"/>
-  <xs:attribute name="target" type="xs:IDREF"/>
-  <xs:attribute name="handler" type="xs:anyURI"/>
-  <xs:attribute name="phase" default="default">
-    <xs:simpleType>
-      <xs:restriction base="xs:NMTOKEN">
-        <xs:enumeration value="capture"/>
-        <xs:enumeration value="default"/>
-      </xs:restriction>
-    </xs:simpleType>
-  </xs:attribute>
-  <xs:attribute name="propagate" default="continue">
-    <xs:simpleType>
-      <xs:restriction base="xs:NMTOKEN">
-        <xs:enumeration value="stop"/>
-        <xs:enumeration value="continue"/>
-      </xs:restriction>
-    </xs:simpleType>
-  </xs:attribute>
-  <xs:attribute name="defaultAction" default="perform">
-    <xs:simpleType>
-      <xs:restriction base="xs:NMTOKEN">
-        <xs:enumeration value="cancel"/>
-        <xs:enumeration value="perform"/>
-      </xs:restriction>
-    </xs:simpleType>
-  </xs:attribute>
-
-  <xs:attributeGroup name="XmlEvents.attlist">
-    <xs:attribute ref="ev:event"/>
-    <xs:attribute ref="ev:observer"/>
-    <xs:attribute ref="ev:target"/>
-    <xs:attribute ref="ev:handler"/>
-    <xs:attribute ref="ev:phase"/>
-    <xs:attribute ref="ev:propagate"/>
-    <xs:attribute ref="ev:defaultAction"/>
-  </xs:attributeGroup>
-
-</xs:schema>
index ea1a17d7e88efd5ec67d377050db30b0909b7597..3f747622195943cb617d1391b344c7b69275eedb 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.acr.xml;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.argeo.api.acr.ArgeoNamespace;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.spi.ProvidedSession;
@@ -52,7 +53,7 @@ class ElementIterator implements Iterator<Content> {
                if (nextElement == null)
                        throw new NoSuchElementException();
                Content result;
-               String isMount = nextElement.getAttributeNS(CrName.CR_NAMESPACE_URI, CrName.mount.qName().getLocalPart());
+               String isMount = nextElement.getAttributeNS(ArgeoNamespace.CR_NAMESPACE_URI, CrName.mount.qName().getLocalPart());
                if (isMount.equals("true")) {
                        result = session.get(parent.getPath() + '/' + nextElement.getTagName());
                }
index 7540455f727b90a39a2762d25ad5f234547c5713..42923997d11a04cbf82aa4daf15798b3b074d5d7 100644 (file)
@@ -13,11 +13,13 @@ import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMResult;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
@@ -34,7 +36,9 @@ public class XmlNormalizer {
 //     private final static Logger logger = System.getLogger(XmlNormalizer.class.getName());
 
        private DocumentBuilder documentBuilder;
-       private Transformer transformer;
+       private TransformerFactory transformerFactory;
+
+       private DOMSource stripSpaceXsl;
 
        public XmlNormalizer() {
                this(2);
@@ -43,12 +47,14 @@ public class XmlNormalizer {
        public XmlNormalizer(int indent) {
                try {
                        documentBuilder = DocumentBuilderFactory.newNSInstance().newDocumentBuilder();
-                       TransformerFactory transformerFactory = TransformerFactory.newInstance();
+                       transformerFactory = TransformerFactory.newInstance();
                        transformerFactory.setAttribute("indent-number", indent);
                        try (InputStream in = XmlNormalizer.class.getResourceAsStream("stripSpaces.xsl")) {
-                               transformer = transformerFactory.newTransformer(new StreamSource(in));
+                               DOMResult result = new DOMResult();
+                               transformerFactory.newTransformer().transform(new StreamSource(in), result);
+                               stripSpaceXsl = new DOMSource(result.getNode());
                        }
-               } catch (TransformerConfigurationException | ParserConfigurationException | TransformerFactoryConfigurationError
+               } catch (ParserConfigurationException | TransformerFactoryConfigurationError | TransformerException
                                | IOException e) {
                        throw new IllegalStateException("Cannot initialise document builder and transformer", e);
                }
@@ -69,11 +75,20 @@ public class XmlNormalizer {
                }
        }
 
-       public void normalizeAndIndent(InputStream in, OutputStream out) throws IOException {
-               normalizeAndIndent(in, out, 2);
+       public void normalizeAndIndent(Source source, Result result) {
+               try {
+                       Transformer transformer = transformerFactory.newTransformer(stripSpaceXsl);
+                       transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+                       // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+                       transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+                       transformer.transform(source, result);
+               } catch (TransformerException e) {
+                       throw new RuntimeException("Cannot strip space from " + source, e);
+               }
        }
 
-       public void normalizeAndIndent(InputStream in, OutputStream out, int indent) throws IOException {
+       public void normalizeAndIndent(InputStream in, OutputStream out) throws IOException {
                try {
                        Document document = documentBuilder.parse(in);
 
@@ -88,17 +103,21 @@ public class XmlNormalizer {
 //                             node.getParentNode().removeChild(node);
 //                     }
 
-                       transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
-                       // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
-                       transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-
-                       transformer.transform(new DOMSource(document), new StreamResult(out));
-               } catch (DOMException | IllegalArgumentException | SAXException | TransformerFactoryConfigurationError
-                               | TransformerException e) {
+                       normalizeAndIndent(new DOMSource(document), new StreamResult(out));
+               } catch (DOMException | IllegalArgumentException | SAXException | TransformerFactoryConfigurationError e) {
                        throw new RuntimeException("Cannot normalise and indent XML", e);
                }
        }
 
+       public static void print(Source source, int indent) {
+               XmlNormalizer xmlNormalizer = new XmlNormalizer(indent);
+               xmlNormalizer.normalizeAndIndent(source, new StreamResult(System.out));
+       }
+
+       public static void print(Source source) {
+               print(source, 2);
+       }
+
        public static void main(String[] args) throws IOException {
                Path dir = Paths.get(args[0]);
                XmlNormalizer xmlNormalizer = new XmlNormalizer();
index d7d6c282ca7fb24ee4a58e2eddcc9aa513146912..289f8dcc65eabf2e101c0af6208bbb2ead05ff90 100644 (file)
@@ -27,7 +27,7 @@ import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.argeo.cms.internal.auth.ImpliedByPrincipal;
 import org.argeo.cms.internal.auth.RemoteCmsSessionImpl;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
-import org.argeo.osgi.useradmin.AuthenticatingUser;
+import org.argeo.cms.osgi.useradmin.AuthenticatingUser;
 import org.osgi.service.useradmin.Authorization;
 
 /** Centralises security related registrations. */
index 6aa1c1c2561b9b12795f39b91a5e45b54fda519b..8834f3587bb2b55886c6b2920e38bb99ac712df1 100644 (file)
@@ -2,24 +2,27 @@ package org.argeo.cms.auth;
 
 import javax.xml.namespace.QName;
 
+import org.argeo.api.acr.ArgeoNamespace;
 import org.argeo.api.acr.ContentName;
-import org.argeo.api.acr.CrName;
+import org.argeo.cms.SystemRole;
 
 /** Standard CMS system roles. */
 public enum CmsRole implements SystemRole {
        userAdmin, //
-       groupAdmin;
+       groupAdmin, //
+       //
+       ;
 
        private final static String QUALIFIER = "cms.";
 
        private final ContentName name;
 
        CmsRole() {
-               name = new ContentName(CrName.ROLE_NAMESPACE_URI, QUALIFIER + name());
+               name = new ContentName(ArgeoNamespace.ROLE_NAMESPACE_URI, QUALIFIER + name());
        }
 
        @Override
-       public QName getName() {
+       public QName qName() {
                return name;
        }
 
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java b/org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java
deleted file mode 100644 (file)
index 2fd8730..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-package org.argeo.cms.auth;
-
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Set;
-import java.util.UUID;
-
-import javax.security.auth.Subject;
-import javax.security.auth.x500.X500Principal;
-
-import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsSession;
-import org.argeo.api.cms.CmsSessionId;
-import org.argeo.cms.internal.auth.CmsSessionImpl;
-import org.argeo.cms.internal.auth.ImpliedByPrincipal;
-import org.argeo.cms.internal.runtime.CmsContextImpl;
-import org.argeo.util.CurrentSubject;
-import org.osgi.service.useradmin.Authorization;
-
-/**
- * Programmatic access to the currently authenticated user, within a CMS
- * context.
- */
-public final class CurrentUser {
-       /*
-        * CURRENT USER API
-        */
-
-       /**
-        * Technical username of the currently authenticated user.
-        * 
-        * @return the authenticated username or null if not authenticated / anonymous
-        */
-       public static String getUsername() {
-               return getUsername(currentSubject());
-       }
-
-       /**
-        * Human readable name of the currently authenticated user (typically first name
-        * and last name).
-        */
-       public static String getDisplayName() {
-               return getDisplayName(currentSubject());
-       }
-
-       /** Whether a user is currently authenticated. */
-       public static boolean isAnonymous() {
-               return isAnonymous(currentSubject());
-       }
-
-       /** Locale of the current user */
-       public final static Locale locale() {
-               return locale(currentSubject());
-       }
-
-       /** Roles of the currently logged-in user */
-       public final static Set<String> roles() {
-               return roles(currentSubject());
-       }
-
-       /** Returns true if the current user is in the specified role */
-       public static boolean isInRole(String role) {
-               Set<String> roles = roles();
-               return roles.contains(role);
-       }
-
-       /** Implies this {@link SystemRole} in this context. */
-       public final static boolean implies(SystemRole role, String context) {
-               return role.implied(currentSubject(), context);
-       }
-
-       /** Implies this {@link SystemRole} in this context. */
-       public final static boolean implies(String role, String context) {
-               return SystemRole.implied(NamespaceUtils.parsePrefixedName(role), currentSubject(), context);
-       }
-
-       /** Executes as the current user */
-       public final static <T> T doAs(PrivilegedAction<T> action) {
-               return Subject.doAs(currentSubject(), action);
-       }
-
-       /** Executes as the current user */
-       public final static <T> T tryAs(PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
-               return Subject.doAs(currentSubject(), action);
-       }
-
-       /*
-        * WRAPPERS
-        */
-
-       public final static String getUsername(Subject subject) {
-               if (subject == null)
-                       throw new IllegalArgumentException("Subject cannot be null");
-               if (subject.getPrincipals(X500Principal.class).size() != 1)
-                       return CmsConstants.ROLE_ANONYMOUS;
-               Principal principal = subject.getPrincipals(X500Principal.class).iterator().next();
-               return principal.getName();
-       }
-
-       public final static String getDisplayName(Subject subject) {
-               return getAuthorization(subject).toString();
-       }
-
-       public final static Set<String> roles(Subject subject) {
-               Set<String> roles = new HashSet<String>();
-               roles.add(getUsername(subject));
-               for (Principal group : subject.getPrincipals(ImpliedByPrincipal.class)) {
-                       roles.add(group.getName());
-               }
-               return roles;
-       }
-
-       public final static Locale locale(Subject subject) {
-               Set<Locale> locales = subject.getPublicCredentials(Locale.class);
-               if (locales.isEmpty()) {
-                       Locale defaultLocale = CmsContextImpl.getCmsContext().getDefaultLocale();
-                       return defaultLocale;
-               } else
-                       return locales.iterator().next();
-       }
-
-       /** Whether this user is currently authenticated. */
-       public static boolean isAnonymous(Subject subject) {
-               if (subject == null)
-                       return true;
-               String username = getUsername(subject);
-               return username == null || username.equalsIgnoreCase(CmsConstants.ROLE_ANONYMOUS);
-       }
-
-       public static CmsSession getCmsSession() {
-               Subject subject = currentSubject();
-               Iterator<CmsSessionId> it = subject.getPrivateCredentials(CmsSessionId.class).iterator();
-               if (!it.hasNext())
-                       throw new IllegalStateException("No CMS session id available for " + subject);
-               CmsSessionId cmsSessionId = it.next();
-               if (it.hasNext())
-                       throw new IllegalStateException("More than one CMS session id available for " + subject);
-               return CmsContextImpl.getCmsContext().getCmsSessionByUuid(cmsSessionId.getUuid());
-       }
-
-       public static boolean isAvailable() {
-               return CurrentSubject.current() != null;
-       }
-
-       /*
-        * HELPERS
-        */
-       private static Subject currentSubject() {
-               Subject subject = CurrentSubject.current();
-               if (subject == null)
-                       throw new IllegalStateException("Cannot find related subject");
-               return subject;
-       }
-
-       private static Authorization getAuthorization(Subject subject) {
-               return subject.getPrivateCredentials(Authorization.class).iterator().next();
-       }
-
-       public static boolean logoutCmsSession(Subject subject) {
-               UUID nodeSessionId;
-               if (subject.getPrivateCredentials(CmsSessionId.class).size() == 1)
-                       nodeSessionId = subject.getPrivateCredentials(CmsSessionId.class).iterator().next().getUuid();
-               else
-                       return false;
-               CmsSessionImpl cmsSession = CmsContextImpl.getCmsContext().getCmsSessionByUuid(nodeSessionId);
-
-               // FIXME logout all views
-               // TODO check why it is sometimes null
-               if (cmsSession != null)
-                       cmsSession.close();
-               // if (log.isDebugEnabled())
-               // log.debug("Logged out CMS session " + cmsSession.getUuid());
-               return true;
-       }
-
-       /** singleton */
-       private CurrentUser() {
-       }
-}
index af559df7558026fc187dbf055181b86dd0deaa68..ebab12f2cc4cd24149787663aa52dad44c651961 100644 (file)
@@ -14,9 +14,9 @@ import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
 
-import org.argeo.cms.security.PBEKeySpecCallback;
-import org.argeo.util.CurrentSubject;
-import org.argeo.util.PasswordEncryption;
+import org.argeo.api.cms.keyring.PBEKeySpecCallback;
+import org.argeo.cms.util.CurrentSubject;
+import org.argeo.cms.util.PasswordEncryption;
 
 /** Adds a secret key to the private credentials */
 public class KeyringLoginModule implements LoginModule {
index f91b6c5decb6955d5790b218caa9bd6f9f88f594..b815b49d192674df0d1628428d7650005307f55c 100644 (file)
@@ -2,6 +2,9 @@ package org.argeo.cms.auth;
 
 /** Transitional interface to decouple from the Servlet API. */
 public interface RemoteAuthResponse {
-       void setHeader(String keys, String value);
+       /** Set this header to a single value, possibly removing previous values. */
+       void setHeader(String headerName, String value);
 
+       /** Add a value to this header. */
+       void addHeader(String headerName, String value);
 }
index 785eeb912f727a5a1246d41927536167f5830a26..3c436ba1fc40edd772e161d65ea1c70bc5f39cea 100644 (file)
@@ -12,10 +12,10 @@ import javax.security.auth.login.LoginException;
 import org.argeo.api.cms.CmsAuth;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsSession;
+import org.argeo.cms.http.HttpHeader;
+import org.argeo.cms.http.HttpStatus;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
-import org.argeo.util.CurrentSubject;
-import org.argeo.util.http.HttpHeader;
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.util.CurrentSubject;
 import org.ietf.jgss.GSSContext;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSManager;
@@ -161,11 +161,15 @@ public class RemoteAuthUtils {
 
                // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
                // realm=\"" + httpAuthRealm + "\"");
-               if (hasAcceptorCredentials() && !forceBasic && !negotiateFailed)// SPNEGO
-                       remoteAuthResponse.setHeader(HttpHeader.WWW_AUTHENTICATE.getHeaderName(), HttpHeader.NEGOTIATE);
-               else
+               if (hasAcceptorCredentials() && !forceBasic && !negotiateFailed) {// SPNEGO
+                       remoteAuthResponse.addHeader(HttpHeader.WWW_AUTHENTICATE.getHeaderName(), HttpHeader.NEGOTIATE);
+                       // TODO make it configurable ?
+                       remoteAuthResponse.addHeader(HttpHeader.WWW_AUTHENTICATE.getHeaderName(),
+                                       HttpHeader.BASIC + " " + HttpHeader.REALM + "=\"" + realm + "\"");
+               } else {
                        remoteAuthResponse.setHeader(HttpHeader.WWW_AUTHENTICATE.getHeaderName(),
                                        HttpHeader.BASIC + " " + HttpHeader.REALM + "=\"" + realm + "\"");
+               }
 
                // response.setDateHeader("Date", System.currentTimeMillis());
                // response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
index d2ceb27a509860ece72d1c36136c70fb053fcb38..987c3dd19dfeff760f579d27adf6f41558812a29 100644 (file)
@@ -16,13 +16,13 @@ import javax.security.auth.spi.LoginModule;
 
 import org.argeo.api.cms.CmsLog;
 import org.argeo.cms.CmsDeployProperty;
+import org.argeo.cms.http.HttpHeader;
 import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
 import org.argeo.cms.internal.runtime.CmsStateImpl;
-import org.argeo.util.http.HttpHeader;
 import org.osgi.service.useradmin.Authorization;
 
-/** Use the HTTP session as the basis for authentication. */
+/** Use a remote session as the basis for authentication. */
 public class RemoteSessionLoginModule implements LoginModule {
        private final static CmsLog log = CmsLog.getLog(RemoteSessionLoginModule.class);
 
@@ -64,8 +64,6 @@ public class RemoteSessionLoginModule implements LoginModule {
                                return false;
                        // TODO factorize with below
                        String httpSessionId = httpSession.getId();
-//                     if (log.isTraceEnabled())
-//                             log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId);
                        CmsSessionImpl cmsSession = CmsContextImpl.getCmsContext().getCmsSessionByLocalId(httpSessionId);
                        if (cmsSession != null && !cmsSession.isAnonymous()) {
                                authorization = cmsSession.getAuthorization();
@@ -77,16 +75,8 @@ public class RemoteSessionLoginModule implements LoginModule {
                        authorization = (Authorization) request.getAttribute(RemoteAuthRequest.AUTHORIZATION);
                        if (authorization == null) {// search by session ID
                                RemoteAuthSession httpSession = request.getSession();
-//                             if (httpSession == null) {
-//                                     // TODO make sure this is always safe
-//                                     if (log.isTraceEnabled())
-//                                             log.trace("Create http session");
-//                                     httpSession = request.createSession();
-//                             }
                                if (httpSession != null) {
                                        String httpSessionId = httpSession.getId();
-//                             if (log.isTraceEnabled())
-//                                     log.trace("HTTP login: " + request.getPathInfo() + " #" + httpSessionId);
                                        CmsSessionImpl cmsSession = CmsContextImpl.getCmsContext().getCmsSessionByLocalId(httpSessionId);
                                        if (cmsSession != null && !cmsSession.isAnonymous()) {
                                                authorization = cmsSession.getAuthorization();
@@ -191,15 +181,6 @@ public class RemoteSessionLoginModule implements LoginModule {
                                }
                        }
                }
-
-               // auth token
-               // String mail = request.getParameter(LdapAttrs.mail.name());
-               // String authPassword = request.getParameter(LdapAttrs.authPassword.name());
-               // if (authPassword != null) {
-               // sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, authPassword);
-               // if (mail != null)
-               // sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, mail);
-               // }
        }
 
        private void extractClientCertificate(RemoteAuthRequest req) {
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/RoleNameUtils.java b/org.argeo.cms/src/org/argeo/cms/auth/RoleNameUtils.java
deleted file mode 100644 (file)
index bf91f39..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.argeo.cms.auth;
-
-public class RoleNameUtils {
-
-       /*
-        * UTILITIES
-        */
-       public final static String getLastRdnValue(String dn) {
-               // we don't use LdapName for portability with Android
-               // TODO make it more robust
-               String[] parts = dn.split(",");
-               String[] rdn = parts[0].split("=");
-               return rdn[1];
-       }
-
-       public final static String getParent(String dn) {
-               int index = dn.indexOf(',');
-               return dn.substring(index + 1);
-       }
-
-       /** Up two levels. */
-       public final static String getContext(String dn) {
-               return getParent(getParent(dn));
-       }
-}
index 35b7d5cc7ebe73233f630e1a46bb6aa2bac2168e..4b36f28abb90f927df087b743f81c09852241319 100644 (file)
@@ -11,10 +11,10 @@ import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
 import javax.security.auth.x500.X500Principal;
 
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.cms.directory.ldap.IpaUtils;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
-import org.argeo.osgi.useradmin.OsUserUtils;
-import org.argeo.util.directory.ldap.IpaUtils;
-import org.argeo.util.naming.LdapAttrs;
+import org.argeo.cms.osgi.useradmin.OsUserUtils;
 import org.osgi.service.useradmin.Authorization;
 
 /** Login module for when the system is owned by a single user. */
@@ -54,7 +54,7 @@ public class SingleUserLoginModule implements LoginModule {
                                throw new LoginException("No username available");
                        String hostname = CmsContextImpl.getCmsContext().getCmsState().getHostname();
                        String baseDn = ("." + hostname).replaceAll("\\.", ",dc=");
-                       X500Principal principal = new X500Principal(LdapAttrs.uid + "=" + username + baseDn);
+                       X500Principal principal = new X500Principal(LdapAttr.uid + "=" + username + baseDn);
                        authorizationName = principal.getName();
                }
 
index a01daf6e0adef7228725ef66833a99d62d66aabb..e5f367d23f1e77cdba3ed26fe806006e8b06a00e 100644 (file)
@@ -36,8 +36,15 @@ public class SpnegoLoginModule implements LoginModule {
        @Override
        public boolean login() throws LoginException {
                byte[] spnegoToken = (byte[]) sharedState.get(CmsAuthUtils.SHARED_STATE_SPNEGO_TOKEN);
-               if (spnegoToken == null)
+               if (spnegoToken == null) {
+                       if (!sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME)) {
+                               // workaround: set shared state name to empty
+                               // in order to avoid Krb5LoginModule printing to System.out
+                               // TODO ask upstream to only log in debug mode
+                               sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, "");
+                       }
                        return false;
+               }
                gssContext = checkToken(spnegoToken);
                if (gssContext == null)
                        return false;
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/SystemRole.java b/org.argeo.cms/src/org/argeo/cms/auth/SystemRole.java
deleted file mode 100644 (file)
index 5d62d98..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.argeo.cms.auth;
-
-import java.util.Set;
-
-import javax.security.auth.Subject;
-import javax.xml.namespace.QName;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.internal.auth.ImpliedByPrincipal;
-
-public interface SystemRole {
-       QName getName();
-
-       default boolean implied(Subject subject, String context) {
-               return implied(getName(), subject, context);
-       }
-
-       static boolean implied(QName name, Subject subject, String context) {
-               Set<ImpliedByPrincipal> roles = subject.getPrincipals(ImpliedByPrincipal.class);
-               for (ImpliedByPrincipal role : roles) {
-                       if (role.isSystemRole()) {
-                               if (role.getRoleName().equals(name)) {
-                                       // !! if context is not specified, it is considered irrelevant
-                                       if (context == null)
-                                               return true;
-                                       if (role.getContext().equalsIgnoreCase(context)
-                                                       || role.getContext().equals(CmsConstants.NODE_BASEDN))
-                                               return true;
-                               }
-                       }
-               }
-               return false;
-
-       }
-}
index 0ae84ff8ac7f294b4b891ac5d77c7281eb10e162..2b5c41ddf8333395ddccf823d14124b5000ddcbf 100644 (file)
@@ -1,8 +1,9 @@
 package org.argeo.cms.auth;
 
-import static org.argeo.util.naming.LdapAttrs.cn;
+import static org.argeo.api.acr.ldap.LdapAttr.cn;
 
 import java.io.IOException;
+import java.security.Principal;
 import java.security.PrivilegedAction;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -24,13 +25,13 @@ import javax.security.auth.login.CredentialNotFoundException;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
 
+import org.argeo.api.acr.ldap.LdapAttr;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.directory.ldap.IpaUtils;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
-import org.argeo.osgi.useradmin.AuthenticatingUser;
-import org.argeo.osgi.useradmin.TokenUtils;
-import org.argeo.util.directory.ldap.IpaUtils;
-import org.argeo.util.naming.LdapAttrs;
+import org.argeo.cms.osgi.useradmin.AuthenticatingUser;
+import org.argeo.cms.osgi.useradmin.TokenUtils;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Group;
 import org.osgi.service.useradmin.User;
@@ -47,8 +48,8 @@ public class UserAdminLoginModule implements LoginModule {
        private CallbackHandler callbackHandler;
        private Map<String, Object> sharedState = null;
 
-       private List<String> indexedUserProperties = Arrays.asList(new String[] { LdapAttrs.mail.name(),
-                       LdapAttrs.uid.name(), LdapAttrs.employeeNumber.name(), LdapAttrs.authPassword.name() });
+       private List<String> indexedUserProperties = Arrays.asList(new String[] { LdapAttr.mail.name(), LdapAttr.uid.name(),
+                       LdapAttr.employeeNumber.name(), LdapAttr.authPassword.name() });
 
        // private state
 //     private BundleContext bc;
@@ -155,20 +156,24 @@ public class UserAdminLoginModule implements LoginModule {
                        return true;// expect Kerberos
 
                if (password != null) {
+                       // TODO disabling bind for the time being,
+                       // as it requires authorisations to be set at LDAP level
+                       boolean tryBind = false;
                        // try bind first
-                       try {
-                               AuthenticatingUser authenticatingUser = new AuthenticatingUser(user.getName(), password);
-                               bindAuthorization = userAdmin.getAuthorization(authenticatingUser);
-                               // TODO check tokens as well
-                               if (bindAuthorization != null) {
-                                       authenticatedUser = user;
-                                       return true;
+                       if (tryBind)
+                               try {
+                                       AuthenticatingUser authenticatingUser = new AuthenticatingUser(user.getName(), password);
+                                       bindAuthorization = userAdmin.getAuthorization(authenticatingUser);
+                                       // TODO check tokens as well
+                                       if (bindAuthorization != null) {
+                                               authenticatedUser = user;
+                                               return true;
+                                       }
+                               } catch (Exception e) {
+                                       // silent
+                                       if (log.isTraceEnabled())
+                                               log.trace("Bind failed", e);
                                }
-                       } catch (Exception e) {
-                               // silent
-                               if (log.isTraceEnabled())
-                                       log.trace("Bind failed", e);
-                       }
 
                        // works only if a connection password is provided
                        if (!user.hasCredential(null, password)) {
@@ -270,8 +275,21 @@ public class UserAdminLoginModule implements LoginModule {
                // Register CmsSession with initial subject
                CmsAuthUtils.registerSessionAuthorization(request, subject, authorization, locale);
 
-               if (log.isDebugEnabled())
-                       log.debug("Logged in to CMS: " + subject);
+               if (log.isDebugEnabled()) {
+                       StringBuilder msg = new StringBuilder();
+                       msg.append("Logged in to CMS: " + authorization.getName() + "(" + authorization + ")\n");
+                       for (Principal principal : subject.getPrincipals()) {
+                               msg.append("  Principal: " + principal.getName()).append(" (")
+                                               .append(principal.getClass().getSimpleName()).append(")\n");
+                       }
+                       for (Object credential : subject.getPublicCredentials()) {
+                               msg.append("  Public Credential: " + credential).append(" (")
+                                               .append(credential.getClass().getSimpleName()).append(")\n");
+                       }
+                       log.debug(msg);
+               }
+//             if (log.isTraceEnabled())
+//                     log.trace(" Subject: " + subject);
                return true;
        }
 
index e3eb442492055e7cbcc02b641ef8f44b2301355c..bef6d7f0a187718c914fc6084f193a3aa7e29137 100644 (file)
@@ -6,8 +6,9 @@ import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 import javax.naming.ldap.Rdn;
 
+import org.argeo.api.acr.ldap.LdapAttr;
 import org.argeo.api.cms.CmsConstants;
-import org.argeo.util.naming.LdapAttrs;
+import org.argeo.cms.CurrentUser;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
@@ -18,7 +19,7 @@ public class UserAdminUtils {
        // CURRENTUSER HELPERS
        /** Checks if current user is the same as the passed one */
        public static boolean isCurrentUser(User user) {
-               String userUsername = getProperty(user, LdapAttrs.DN);
+               String userUsername = getProperty(user, LdapAttr.DN);
                LdapName userLdapName = getLdapName(userUsername);
                LdapName selfUserName = getCurrentUserLdapName();
                return userLdapName.equals(selfUserName);
@@ -43,7 +44,7 @@ public class UserAdminUtils {
 
        /** Retrieves the current logged-in user common name */
        public final static String getCommonName(User user) {
-               return getProperty(user, LdapAttrs.cn.name());
+               return getProperty(user, LdapAttr.cn.name());
        }
 
        // OTHER USERS HELPERS
@@ -54,8 +55,8 @@ public class UserAdminUtils {
        public static String getUserLocalId(String dn) {
                LdapName ldapName = getLdapName(dn);
                Rdn last = ldapName.getRdn(ldapName.size() - 1);
-               if (last.getType().toLowerCase().equals(LdapAttrs.uid.name())
-                               || last.getType().toLowerCase().equals(LdapAttrs.cn.name()))
+               if (last.getType().toLowerCase().equals(LdapAttr.uid.name())
+                               || last.getType().toLowerCase().equals(LdapAttr.cn.name()))
                        return (String) last.getValue();
                else
                        throw new IllegalArgumentException("Cannot retrieve user local id, non valid dn: " + dn);
@@ -73,11 +74,11 @@ public class UserAdminUtils {
        }
 
        public static String getUserDisplayName(Role user) {
-               String dName = getProperty(user, LdapAttrs.displayName.name());
+               String dName = getProperty(user, LdapAttr.displayName.name());
                if (isEmpty(dName))
-                       dName = getProperty(user, LdapAttrs.cn.name());
+                       dName = getProperty(user, LdapAttr.cn.name());
                if (isEmpty(dName))
-                       dName = getProperty(user, LdapAttrs.uid.name());
+                       dName = getProperty(user, LdapAttr.uid.name());
                if (isEmpty(dName))
                        dName = getUserLocalId(user.getName());
                return dName;
@@ -92,7 +93,7 @@ public class UserAdminUtils {
                if (user == null)
                        return null;
                else
-                       return getProperty(user, LdapAttrs.mail.name());
+                       return getProperty(user, LdapAttr.mail.name());
        }
 
        // LDAP NAMES HELPERS
@@ -125,7 +126,7 @@ public class UserAdminUtils {
        }
 
        /**
-        * Simply retrieves a LDAP name from a {@link LdapAttrs.DN} with no exception
+        * Simply retrieves a LDAP name from a {@link LdapAttr.DN} with no exception
         */
        private static LdapName getLdapName(String dn) {
                try {
@@ -150,8 +151,8 @@ public class UserAdminUtils {
                        int i = 0;
                        loop: while (i < rdns.size()) {
                                Rdn currrRdn = rdns.get(i);
-                               if (LdapAttrs.uid.name().equals(currrRdn.getType()) || LdapAttrs.cn.name().equals(currrRdn.getType())
-                                               || LdapAttrs.ou.name().equals(currrRdn.getType()))
+                               if (LdapAttr.uid.name().equals(currrRdn.getType()) || LdapAttr.cn.name().equals(currrRdn.getType())
+                                               || LdapAttr.ou.name().equals(currrRdn.getType()))
                                        break loop;
                                else {
                                        String currVal = (String) currrRdn.getValue();
diff --git a/org.argeo.cms/src/org/argeo/cms/client/CmsClient.java b/org.argeo.cms/src/org/argeo/cms/client/CmsClient.java
new file mode 100644 (file)
index 0000000..8cfae3a
--- /dev/null
@@ -0,0 +1,172 @@
+package org.argeo.cms.client;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.http.HttpResponse.BodyHandler;
+import java.net.http.HttpResponse.BodyHandlers;
+import java.net.http.WebSocket;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.cms.auth.ConsoleCallbackHandler;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.cms.http.HttpHeader;
+
+/** Utility to connect to a remote CMS node. */
+public class CmsClient {
+       public final static String CLIENT_LOGIN_CONTEXT = "CLIENT";
+
+       private URI uri;
+
+       private HttpClient httpClient;
+       private String gssToken;
+
+       public CmsClient(URI uri) {
+               this.uri = uri;
+       }
+
+       public void login() {
+               String server = uri.getHost();
+
+               URL jaasUrl = CmsClient.class.getResource("jaas-client-ipa.cfg");
+               System.setProperty("java.security.auth.login.config", jaasUrl.toExternalForm());
+               try {
+                       LoginContext lc = new LoginContext(CLIENT_LOGIN_CONTEXT, new ConsoleCallbackHandler());
+                       lc.login();
+                       gssToken = RemoteAuthUtils.createGssToken(lc.getSubject(), "HTTP", server);
+               } catch (LoginException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               } finally {
+
+               }
+       }
+
+       public String getAsString() {
+               return getAsString(uri);
+       }
+
+       public String getAsString(URI uri) {
+               uri = normalizeUri(uri);
+               try {
+                       HttpClient httpClient = getHttpClient();
+
+                       HttpRequest request = HttpRequest.newBuilder().uri(uri) //
+                                       .header(HttpHeader.AUTHORIZATION.getHeaderName(), HttpHeader.NEGOTIATE + " " + getGssToken()) //
+                                       .build();
+                       BodyHandler<String> bodyHandler = BodyHandlers.ofString();
+                       HttpResponse<String> response = httpClient.send(request, bodyHandler);
+                       return response.body();
+//                     int responseCode = response.statusCode();
+//                     System.exit(responseCode);
+               } catch (IOException | InterruptedException e) {
+                       throw new RuntimeException("Cannot read " + uri + " as a string", e);
+               }
+       }
+
+       protected URI normalizeUri(URI uri) {
+               if (uri.getHost() != null)
+                       return uri;
+               try {
+                       String path = uri.getPath();
+                       if (path.startsWith("/")) {// absolute
+                               return new URI(this.uri.getScheme(), this.uri.getUserInfo(), this.uri.getHost(), this.uri.getPort(),
+                                               path, uri.getQuery(), uri.getFragment());
+                       } else {
+                               String thisUriStr = this.uri.toString();
+                               if (!thisUriStr.endsWith("/"))
+                                       thisUriStr = thisUriStr + "/";
+                               return URI.create(thisUriStr + path);
+                       }
+               } catch (URISyntaxException e) {
+                       throw new IllegalArgumentException("Cannot interpret " + uri, e);
+               }
+       }
+
+       public URI getUri() {
+               return uri;
+       }
+
+       String getGssToken() {
+               return gssToken;
+       }
+
+       public HttpClient getHttpClient() {
+               if (httpClient == null) {
+                       login();
+                       HttpClient client = HttpClient.newBuilder() //
+                                       .sslContext(ipaSslContext()) //
+                                       .version(HttpClient.Version.HTTP_1_1) //
+                                       .build();
+                       httpClient = client;
+               }
+               return httpClient;
+       }
+
+       public CompletableFuture<WebSocket> newWebSocket(WebSocket.Listener listener) {
+               return newWebSocket(uri, listener);
+       }
+
+       public CompletableFuture<WebSocket> newWebSocket(URI uri, WebSocket.Listener listener) {
+               CompletableFuture<WebSocket> ws = getHttpClient().newWebSocketBuilder()
+                               .header(HttpHeader.AUTHORIZATION.getHeaderName(), HttpHeader.NEGOTIATE + " " + getGssToken())
+                               .buildAsync(uri, listener);
+               return ws;
+       }
+
+       @SuppressWarnings("unchecked")
+       protected SSLContext ipaSslContext() {
+               try {
+                       final Collection<X509Certificate> certificates;
+                       Path caCertificatePath = Paths.get("/etc/ipa/ca.crt");
+                       if (Files.exists(caCertificatePath)) {
+                               CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
+                               try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(caCertificatePath))) {
+                                       certificates = (Collection<X509Certificate>) certificateFactory.generateCertificates(in);
+                               }
+                       } else {
+                               certificates = null;
+                       }
+                       TrustManager[] noopTrustManager = new TrustManager[] { new X509TrustManager() {
+                               public void checkClientTrusted(X509Certificate[] xcs, String string) {
+                               }
+
+                               public void checkServerTrusted(X509Certificate[] xcs, String string) {
+                               }
+
+                               public X509Certificate[] getAcceptedIssuers() {
+                                       if (certificates == null)
+                                               return null;
+                                       return certificates.toArray(new X509Certificate[certificates.size()]);
+                               }
+                       } };
+
+                       SSLContext sc = SSLContext.getInstance("ssl");
+                       sc.init(null, noopTrustManager, null);
+                       return sc;
+               } catch (KeyManagementException | NoSuchAlgorithmException | CertificateException | IOException e) {
+                       throw new IllegalStateException("Cannot create SSL context ", e);
+               }
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/client/SpnegoHttpClient.java b/org.argeo.cms/src/org/argeo/cms/client/SpnegoHttpClient.java
deleted file mode 100644 (file)
index 444f4ef..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.argeo.cms.client;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.net.http.HttpResponse.BodyHandler;
-import java.net.http.HttpResponse.BodyHandlers;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.Collection;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-
-import org.argeo.cms.auth.ConsoleCallbackHandler;
-import org.argeo.cms.auth.RemoteAuthUtils;
-import org.argeo.util.http.HttpHeader;
-
-public class SpnegoHttpClient {
-       public final static String CLIENT_LOGIN_CONTEXT = "CLIENT";
-
-       public static void main(String[] args) throws MalformedURLException {
-//             String principal = System.getProperty("javax.security.auth.login.name");
-               if (args.length == 0) {
-                       System.err.println("usage: java -Djavax.security.auth.login.name=<principal@REALM> "
-                                       + SpnegoHttpClient.class.getName() + " <url>");
-                       System.exit(1);
-                       return;
-               }
-               String url = args[0];
-               URL u = new URL(url);
-               String server = u.getHost();
-
-               URL jaasUrl = SpnegoHttpClient.class.getResource("jaas-client-ipa.cfg");
-               System.setProperty("java.security.auth.login.config", jaasUrl.toExternalForm());
-               try {
-                       LoginContext lc = new LoginContext(CLIENT_LOGIN_CONTEXT, new ConsoleCallbackHandler());
-                       lc.login();
-
-                       HttpClient httpClient = openHttpClient(lc.getSubject());
-                       String token = RemoteAuthUtils.createGssToken(lc.getSubject(), "HTTP", server);
-
-                       HttpRequest request = HttpRequest.newBuilder().uri(u.toURI()) //
-                                       .header(HttpHeader.AUTHORIZATION.getHeaderName(), HttpHeader.NEGOTIATE + " " + token) //
-                                       .build();
-                       BodyHandler<String> bodyHandler = BodyHandlers.ofString();
-                       HttpResponse<String> response = httpClient.send(request, bodyHandler);
-                       System.out.println(response.body());
-                       int responseCode = response.statusCode();
-                       System.exit(responseCode);
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-       }
-
-       static HttpClient openHttpClient(Subject subject) {
-               HttpClient client = HttpClient.newBuilder() //
-                               .sslContext(ipaSslContext()) //
-                               .version(HttpClient.Version.HTTP_1_1) //
-                               .build();
-
-               return client;
-       }
-
-       @SuppressWarnings("unchecked")
-       static SSLContext ipaSslContext() {
-               try {
-                       final Collection<X509Certificate> certificates;
-                       Path caCertificatePath = Paths.get("/etc/ipa/ca.crt");
-                       if (Files.exists(caCertificatePath)) {
-                               CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
-                               try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(caCertificatePath))) {
-                                       certificates = (Collection<X509Certificate>) certificateFactory.generateCertificates(in);
-                               }
-                       } else {
-                               certificates = null;
-                       }
-                       TrustManager[] noopTrustManager = new TrustManager[] { new X509TrustManager() {
-                               public void checkClientTrusted(X509Certificate[] xcs, String string) {
-                               }
-
-                               public void checkServerTrusted(X509Certificate[] xcs, String string) {
-                               }
-
-                               public X509Certificate[] getAcceptedIssuers() {
-                                       if (certificates == null)
-                                               return null;
-                                       return certificates.toArray(new X509Certificate[certificates.size()]);
-                               }
-                       } };
-
-                       SSLContext sc = SSLContext.getInstance("ssl");
-                       sc.init(null, noopTrustManager, null);
-                       return sc;
-               } catch (KeyManagementException | NoSuchAlgorithmException | CertificateException | IOException e) {
-                       throw new IllegalStateException("Cannot create SSL context ", e);
-               }
-       }
-
-}
index 294b485fb450668352baac32a63e457ebd30233d..e8dd2fa523f4c2305e42b6fd21353ff93fc9a61e 100644 (file)
@@ -1,65 +1,60 @@
 package org.argeo.cms.client;
 
 import java.net.URI;
-import java.net.URL;
-import java.net.http.HttpClient;
 import java.net.http.WebSocket;
 import java.nio.ByteBuffer;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
-
-import javax.security.auth.login.LoginContext;
-
-import org.argeo.cms.auth.RemoteAuthUtils;
-import org.argeo.util.http.HttpHeader;
+import java.util.concurrent.ExecutionException;
 
 /** Tests connectivity to the web socket server. */
-public class WebSocketEventClient {
+public class WebSocketEventClient implements Runnable {
 
-       public static void main(String[] args) throws Exception {
-               if (args.length == 0) {
-                       System.err.println("usage: java " + WebSocketEventClient.class.getName() + " <url>");
-                       System.exit(1);
-                       return;
-               }
-               URI uri = URI.create(args[0]);
-               WebSocket.Listener listener = new WebSocket.Listener() {
+       private final URI uri;
 
-                       public CompletionStage<?> onText(WebSocket webSocket, CharSequence message, boolean last) {
-                               System.out.println(message);
-                               CompletionStage<String> res = CompletableFuture.completedStage(message.toString());
-                               return res;
-                       }
+       private WebSocket webSocket;
 
-                       @Override
-                       public CompletionStage<?> onPong(WebSocket webSocket, ByteBuffer message) {
-                               // System.out.println("Pong received.");
-                               return null;
-                       }
-
-               };
+       private CmsClient cmsClient;
 
-               // SPNEGO
-               URL jaasUrl = SpnegoHttpClient.class.getResource("jaas-client-ipa.cfg");
-               System.setProperty("java.security.auth.login.config", jaasUrl.toExternalForm());
-               LoginContext lc = new LoginContext(SpnegoHttpClient.CLIENT_LOGIN_CONTEXT);
-               lc.login();
-               String token = RemoteAuthUtils.createGssToken(lc.getSubject(), "HTTP", uri.getHost());
+       public WebSocketEventClient(URI uri) {
+               this.uri = uri;
+               cmsClient = new CmsClient(uri);
+       }
 
-               HttpClient client = SpnegoHttpClient.openHttpClient(lc.getSubject());
-               CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
-                               .header(HttpHeader.AUTHORIZATION.getHeaderName(), HttpHeader.NEGOTIATE + " " + token)
-                               .buildAsync(uri, listener);
+       @Override
+       public void run() {
+               try {
+                       CompletableFuture<WebSocket> ws = cmsClient.newWebSocket(new WsEventListener());
 
-               WebSocket webSocket = ws.get();
-               webSocket.request(Long.MAX_VALUE);
+                       WebSocket webSocket = ws.get();
+                       webSocket.request(Long.MAX_VALUE);
 
-               Runtime.getRuntime().addShutdownHook(new Thread(() -> webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "")));
+                       Runtime.getRuntime().addShutdownHook(new Thread(() -> webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "")));
 
-               while (!webSocket.isInputClosed()) {
-                       webSocket.sendPing(ByteBuffer.allocate(0));
-                       Thread.sleep(10000);
+                       while (!webSocket.isInputClosed()) {
+                               webSocket.sendPing(ByteBuffer.allocate(0));
+                               Thread.sleep(10000);
+                       }
+               } catch (InterruptedException e) {
+                       if (webSocket != null)
+                               webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "");
+               } catch (ExecutionException e) {
+                       throw new RuntimeException("Cannot listent to " + uri, e.getCause());
                }
        }
 
+       private class WsEventListener implements WebSocket.Listener {
+               public CompletionStage<?> onText(WebSocket webSocket, CharSequence message, boolean last) {
+                       System.out.println(message);
+                       CompletionStage<String> res = CompletableFuture.completedStage(message.toString());
+                       return res;
+               }
+
+               @Override
+               public CompletionStage<?> onPong(WebSocket webSocket, ByteBuffer message) {
+                       // System.out.println("Pong received.");
+                       return null;
+               }
+
+       }
 }
diff --git a/org.argeo.cms/src/org/argeo/cms/client/WebSocketPing.java b/org.argeo.cms/src/org/argeo/cms/client/WebSocketPing.java
new file mode 100644 (file)
index 0000000..808c8de
--- /dev/null
@@ -0,0 +1,90 @@
+package org.argeo.cms.client;
+
+import java.math.RoundingMode;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.WebSocket;
+import java.nio.ByteBuffer;
+import java.text.DecimalFormat;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
+
+/** Tests connectivity to the web socket server. */
+public class WebSocketPing implements Runnable {
+       private final static int PING_FRAME_SIZE = 125;
+       private final static DecimalFormat decimalFormat = new DecimalFormat("0.0");
+       static {
+               decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
+       }
+
+       private final URI uri;
+       private final UUID uuid;
+
+       private WebSocket webSocket;
+
+       public WebSocketPing(URI uri) {
+               this.uri = uri;
+               this.uuid = UUID.randomUUID();
+       }
+
+       @Override
+       public void run() {
+               try {
+                       WebSocket.Listener listener = new WebSocket.Listener() {
+
+                               @Override
+                               public CompletionStage<?> onPong(WebSocket webSocket, ByteBuffer message) {
+                                       long msb = message.getLong();
+                                       long lsb = message.getLong();
+                                       long end = System.nanoTime();
+                                       if (msb != uuid.getMostSignificantBits() || lsb != uuid.getLeastSignificantBits())
+                                               return null; // ignore
+                                       long begin = message.getLong();
+                                       double durationNs = end - begin;
+                                       double durationMs = durationNs / 1000000;
+                                       int size = message.remaining() + (3 * Long.BYTES);
+                                       System.out.println(
+                                                       size + " bytes from " + uri + ": time=" + decimalFormat.format(durationMs) + " ms");
+                                       return null;
+                               }
+
+                       };
+
+                       HttpClient client = HttpClient.newHttpClient();
+                       CompletableFuture<WebSocket> ws = client.newWebSocketBuilder().buildAsync(uri, listener);
+                       webSocket = ws.get();
+                       webSocket.request(Long.MAX_VALUE);
+
+                       Runtime.getRuntime().addShutdownHook(new Thread(() -> webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "")));
+
+                       while (!webSocket.isInputClosed()) {
+                               long begin = System.nanoTime();
+                               ByteBuffer buffer = ByteBuffer.allocate(PING_FRAME_SIZE);
+                               buffer.putLong(uuid.getMostSignificantBits());
+                               buffer.putLong(uuid.getLeastSignificantBits());
+                               buffer.putLong(begin);
+                               buffer.flip();
+                               webSocket.sendPing(buffer);
+                               Thread.sleep(1000);
+                       }
+               } catch (InterruptedException e) {
+                       if (webSocket != null)
+                               webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "");
+               } catch (ExecutionException e) {
+                       throw new RuntimeException("Cannot ping " + uri, e.getCause());
+               }
+       }
+
+//     public static void main(String[] args) throws Exception {
+//             if (args.length == 0) {
+//                     System.err.println("usage: java " + WsPing.class.getName() + " <url>");
+//                     System.exit(1);
+//                     return;
+//             }
+//             URI uri = URI.create(args[0]);
+//             new WsPing(uri).run();
+//     }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/client/WsPing.java b/org.argeo.cms/src/org/argeo/cms/client/WsPing.java
deleted file mode 100644 (file)
index 55d6f04..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.argeo.cms.client;
-
-import java.math.RoundingMode;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.WebSocket;
-import java.nio.ByteBuffer;
-import java.text.DecimalFormat;
-import java.util.UUID;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.concurrent.ExecutionException;
-
-/** Tests connectivity to the web socket server. */
-public class WsPing implements Runnable {
-       private final static int PING_FRAME_SIZE = 125;
-
-       private final URI uri;
-       private final UUID uuid;
-
-       private final DecimalFormat decimalFormat;
-
-       public WsPing(URI uri) {
-               this.uri = uri;
-               this.uuid = UUID.randomUUID();
-               decimalFormat = new DecimalFormat("0.0");
-               decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
-       }
-
-       @Override
-       public void run() {
-               try {
-                       WebSocket.Listener listener = new WebSocket.Listener() {
-
-                               @Override
-                               public CompletionStage<?> onPong(WebSocket webSocket, ByteBuffer message) {
-                                       long msb = message.getLong();
-                                       long lsb = message.getLong();
-                                       long end = System.nanoTime();
-                                       if (msb != uuid.getMostSignificantBits() || lsb != uuid.getLeastSignificantBits())
-                                               return null; // ignore
-                                       long begin = message.getLong();
-                                       double durationNs = end - begin;
-                                       double durationMs = durationNs / 1000000;
-                                       int size = message.remaining() + (3 * Long.BYTES);
-                                       System.out.println(
-                                                       size + " bytes from " + uri + ": time=" + decimalFormat.format(durationMs) + " ms");
-                                       return null;
-                               }
-
-                       };
-
-                       HttpClient client = HttpClient.newHttpClient();
-                       CompletableFuture<WebSocket> ws = client.newWebSocketBuilder().buildAsync(uri, listener);
-                       WebSocket webSocket = ws.get();
-                       webSocket.request(Long.MAX_VALUE);
-
-                       Runtime.getRuntime().addShutdownHook(new Thread(() -> webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "")));
-
-                       while (!webSocket.isInputClosed()) {
-                               long begin = System.nanoTime();
-                               ByteBuffer buffer = ByteBuffer.allocate(PING_FRAME_SIZE);
-                               buffer.putLong(uuid.getMostSignificantBits());
-                               buffer.putLong(uuid.getLeastSignificantBits());
-                               buffer.putLong(begin);
-                               buffer.flip();
-                               webSocket.sendPing(buffer);
-                               Thread.sleep(1000);
-                       }
-               } catch (InterruptedException | ExecutionException e) {
-                       e.printStackTrace();
-               }
-       }
-
-       public static void main(String[] args) throws Exception {
-               if (args.length == 0) {
-                       System.err.println("usage: java " + WsPing.class.getName() + " <url>");
-                       System.exit(1);
-                       return;
-               }
-               URI uri = URI.create(args[0]);
-               new WsPing(uri).run();
-       }
-
-}
index 2921a339738ebdc3164323a134e5064db04dc261..b776c2c5ce6ed90ca7c6774a48e771997037d7f9 100644 (file)
@@ -1,4 +1,4 @@
 CLIENT {
     com.sun.security.auth.module.Krb5LoginModule required
-    useTicketCache=true;
+     useTicketCache=true;
 };
index 94f292c8e68cd70e2b3c38201a04959332cf0904..6fe2eb617cf0862c8ce62b121d4a3edd481153c1 100644 (file)
@@ -15,9 +15,9 @@ import java.util.Iterator;
 
 import javax.xml.namespace.QName;
 
-import org.argeo.util.http.HttpHeader;
-import org.argeo.util.http.HttpMethod;
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.http.HttpHeader;
+import org.argeo.cms.http.HttpMethod;
+import org.argeo.cms.http.HttpStatus;
 
 public class DavClient {
 
index 24695e7b1fc52c737503bc134898a910dfe18b53..c7542b55aa7f551c7c7338c8fd79ae5f71711ebf 100644 (file)
@@ -1,6 +1,6 @@
 package org.argeo.cms.dav;
 
-import org.argeo.util.http.HttpHeader;
+import org.argeo.cms.http.HttpHeader;
 
 import com.sun.net.httpserver.HttpExchange;
 
index 1d6c02623d7bf40d3049b53849b704e437547ef5..63f4f82c7574b5d936fdeb1336bfd7296f758cbf 100644 (file)
@@ -10,10 +10,10 @@ import java.util.function.Consumer;
 import javax.xml.namespace.NamespaceContext;
 
 import org.argeo.api.acr.ContentNotFoundException;
-import org.argeo.util.http.HttpHeader;
-import org.argeo.util.http.HttpMethod;
-import org.argeo.util.http.HttpStatus;
-import org.argeo.util.http.HttpServerUtils;
+import org.argeo.cms.http.HttpHeader;
+import org.argeo.cms.http.HttpMethod;
+import org.argeo.cms.http.HttpStatus;
+import org.argeo.cms.http.server.HttpServerUtils;
 
 import com.sun.net.httpserver.HttpExchange;
 import com.sun.net.httpserver.HttpHandler;
index 828dc2640902d7571e91fa0b1cc8e6aa3b2f76df..8dd6bf3fc2cde0742d39675f550f74a271791656 100644 (file)
@@ -10,7 +10,7 @@ import java.util.TreeSet;
 
 import javax.xml.namespace.QName;
 
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.http.HttpStatus;
 
 /** The WebDav response for a given resource. */
 public class DavResponse {
index 6d22c8e295f959822cf3ffb0a0ebfa6868d1c22e..c7b54b0273324aa3cf273025fc9db09d0be03bed 100644 (file)
@@ -19,7 +19,7 @@ import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.http.HttpStatus;
 
 /**
  * Asynchronously iterate over the response statuses of the response to a
index 986b2fe9271c665fda435b399f7124d37e9a0a14..4689b8c8d346c67262512b5c2025b4b80eebfe54 100644 (file)
@@ -20,7 +20,7 @@ import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.http.HttpStatus;
 
 class MultiStatusWriter implements Consumer<DavResponse> {
        private BlockingQueue<DavResponse> queue = new ArrayBlockingQueue<>(64);
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectory.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectory.java
new file mode 100644 (file)
index 0000000..5dffcb6
--- /dev/null
@@ -0,0 +1,582 @@
+package org.argeo.cms.directory.ldap;
+
+import static org.argeo.cms.directory.ldap.LdapNameUtils.toLdapName;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.transaction.xa.XAResource;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.acr.ldap.LdapObj;
+import org.argeo.api.cms.directory.CmsDirectory;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.api.cms.transaction.WorkControl;
+import org.argeo.api.cms.transaction.WorkingCopyXaResource;
+import org.argeo.api.cms.transaction.XAResourceProvider;
+import org.argeo.cms.osgi.useradmin.OsUserDirectory;
+import org.argeo.cms.runtime.DirectoryConf;
+
+/** A {@link CmsDirectory} based either on LDAP or LDIF. */
+public abstract class AbstractLdapDirectory implements CmsDirectory, XAResourceProvider {
+       protected static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
+       protected static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
+
+       private final LdapName baseDn;
+       private final Hashtable<String, Object> configProperties;
+       private final Rdn userBaseRdn, groupBaseRdn, systemRoleBaseRdn;
+       private final String userObjectClass, groupObjectClass;
+       private String memberAttributeId = "member";
+
+       private final boolean readOnly;
+       private final boolean disabled;
+       private final String uri;
+
+       private String forcedPassword;
+
+       private final boolean scoped;
+
+       private List<String> credentialAttributeIds = Arrays
+                       .asList(new String[] { LdapAttr.userPassword.name(), LdapAttr.authPassword.name() });
+
+       private WorkControl transactionControl;
+       private WorkingCopyXaResource<LdapEntryWorkingCopy> xaResource;
+
+       private LdapDirectoryDao directoryDao;
+
+       /** Whether the the directory has is authenticated via a service user. */
+       private boolean authenticated = false;
+
+       public AbstractLdapDirectory(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
+               this.configProperties = new Hashtable<String, Object>();
+               for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
+                       String key = keys.nextElement();
+                       configProperties.put(key, props.get(key));
+               }
+
+               String baseDnStr = DirectoryConf.baseDn.getValue(configProperties);
+               if (baseDnStr == null)
+                       throw new IllegalArgumentException("Base DN must be specified: " + configProperties);
+               baseDn = toLdapName(baseDnStr);
+               this.scoped = scoped;
+
+               if (uriArg != null) {
+                       uri = uriArg.toString();
+                       // uri from properties is ignored
+               } else {
+                       String uriStr = DirectoryConf.uri.getValue(configProperties);
+                       if (uriStr == null)
+                               uri = null;
+                       else
+                               uri = uriStr;
+               }
+
+               forcedPassword = DirectoryConf.forcedPassword.getValue(configProperties);
+
+               userObjectClass = DirectoryConf.userObjectClass.getValue(configProperties);
+               groupObjectClass = DirectoryConf.groupObjectClass.getValue(configProperties);
+
+               String userBase = DirectoryConf.userBase.getValue(configProperties);
+               String groupBase = DirectoryConf.groupBase.getValue(configProperties);
+               String systemRoleBase = DirectoryConf.systemRoleBase.getValue(configProperties);
+               try {
+//                     baseDn = new LdapName(UserAdminConf.baseDn.getValue(properties));
+                       userBaseRdn = new Rdn(userBase);
+//                     userBaseDn = new LdapName(userBase + "," + baseDn);
+                       groupBaseRdn = new Rdn(groupBase);
+//                     groupBaseDn = new LdapName(groupBase + "," + baseDn);
+                       systemRoleBaseRdn = new Rdn(systemRoleBase);
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException(
+                                       "Badly formated base DN " + DirectoryConf.baseDn.getValue(configProperties), e);
+               }
+
+               // read only
+               String readOnlyStr = DirectoryConf.readOnly.getValue(configProperties);
+               if (readOnlyStr == null) {
+                       readOnly = readOnlyDefault(uri);
+                       configProperties.put(DirectoryConf.readOnly.name(), Boolean.toString(readOnly));
+               } else
+                       readOnly = Boolean.parseBoolean(readOnlyStr);
+
+               // disabled
+               String disabledStr = DirectoryConf.disabled.getValue(configProperties);
+               if (disabledStr != null)
+                       disabled = Boolean.parseBoolean(disabledStr);
+               else
+                       disabled = false;
+               if (!getRealm().isEmpty()) {
+                       // IPA multiple LDAP causes URI parsing to fail
+                       // TODO manage generic redundant LDAP case
+                       directoryDao = new LdapDao(this);
+               } else {
+                       if (uri != null) {
+                               URI u = URI.create(uri);
+                               if (DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
+                                               || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
+                                       directoryDao = new LdapDao(this);
+                                       authenticated = configProperties.get(Context.SECURITY_PRINCIPAL) != null;
+                               } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
+                                       directoryDao = new LdifDao(this);
+                                       authenticated = true;
+                               } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
+                                       directoryDao = new OsUserDirectory(this);
+                                       authenticated = true;
+                                       // singleUser = true;
+                               } else {
+                                       throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
+                               }
+                       } else {
+                               // in memory
+                               directoryDao = new LdifDao(this);
+                       }
+               }
+               if (directoryDao != null)
+                       xaResource = new WorkingCopyXaResource<>(directoryDao);
+       }
+
+       /*
+        * INITIALISATION
+        */
+
+       public void init() {
+               getDirectoryDao().init();
+       }
+
+       public void destroy() {
+               getDirectoryDao().destroy();
+       }
+
+       /*
+        * CREATION
+        */
+       protected abstract LdapEntry newUser(LdapName name);
+
+       protected abstract LdapEntry newGroup(LdapName name);
+
+       /*
+        * EDITION
+        */
+
+       public boolean isEditing() {
+               return xaResource.wc() != null;
+       }
+
+       public LdapEntryWorkingCopy getWorkingCopy() {
+               LdapEntryWorkingCopy wc = xaResource.wc();
+               if (wc == null)
+                       return null;
+               return wc;
+       }
+
+       public void checkEdit() {
+               if (xaResource.wc() == null) {
+                       try {
+                               transactionControl.getWorkContext().registerXAResource(xaResource, null);
+                       } catch (Exception e) {
+                               throw new IllegalStateException("Cannot enlist " + xaResource, e);
+                       }
+               } else {
+               }
+       }
+
+       public void setTransactionControl(WorkControl transactionControl) {
+               this.transactionControl = transactionControl;
+       }
+
+       public XAResource getXaResource() {
+               return xaResource;
+       }
+
+       public boolean removeEntry(LdapName dn) {
+               checkEdit();
+               LdapEntryWorkingCopy wc = getWorkingCopy();
+               boolean actuallyDeleted;
+               if (getDirectoryDao().entryExists(dn) || wc.getNewData().containsKey(dn)) {
+                       LdapEntry user = doGetRole(dn);
+                       wc.getDeletedData().put(dn, user);
+                       actuallyDeleted = true;
+               } else {// just removing from groups (e.g. system roles)
+                       actuallyDeleted = false;
+               }
+               for (LdapName groupDn : getDirectoryDao().getDirectGroups(dn)) {
+                       LdapEntry group = doGetRole(groupDn);
+                       group.getAttributes().get(getMemberAttributeId()).remove(dn.toString());
+               }
+               return actuallyDeleted;
+       }
+
+       /*
+        * RETRIEVAL
+        */
+
+       protected LdapEntry doGetRole(LdapName dn) {
+               LdapEntryWorkingCopy wc = getWorkingCopy();
+               LdapEntry user;
+               try {
+                       user = getDirectoryDao().doGetEntry(dn);
+               } catch (NameNotFoundException e) {
+                       user = null;
+               }
+               if (wc != null) {
+                       if (user == null && wc.getNewData().containsKey(dn))
+                               user = wc.getNewData().get(dn);
+                       else if (wc.getDeletedData().containsKey(dn))
+                               user = null;
+               }
+               return user;
+       }
+
+       protected void collectGroups(LdapEntry user, List<LdapEntry> allRoles) {
+               Attributes attrs = user.getAttributes();
+               // TODO centralize attribute name
+               Attribute memberOf = attrs.get(LdapAttr.memberOf.name());
+               // if user belongs to this directory, we only check memberOf
+               if (memberOf != null && user.getDn().startsWith(getBaseDn())) {
+                       try {
+                               NamingEnumeration<?> values = memberOf.getAll();
+                               while (values.hasMore()) {
+                                       Object value = values.next();
+                                       LdapName groupDn = new LdapName(value.toString());
+                                       LdapEntry group = doGetRole(groupDn);
+                                       if (group != null) {
+                                               allRoles.add(group);
+                                       } else {
+                                               // user doesn't have the right to retrieve role, but we know it exists
+                                               // otherwise memberOf would not work
+                                               group = newGroup(groupDn);
+                                               allRoles.add(group);
+                                       }
+                               }
+                       } catch (NamingException e) {
+                               throw new IllegalStateException("Cannot get memberOf groups for " + user, e);
+                       }
+               } else {
+                       directGroups: for (LdapName groupDn : getDirectoryDao().getDirectGroups(user.getDn())) {
+                               LdapEntry group = doGetRole(groupDn);
+                               if (group != null) {
+                                       if (allRoles.contains(group)) {
+                                               // important in order to avoi loops
+                                               continue directGroups;
+                                       }
+                                       allRoles.add(group);
+                                       collectGroups(group, allRoles);
+                               }
+                       }
+               }
+       }
+
+       /*
+        * HIERARCHY
+        */
+       @Override
+       public HierarchyUnit getHierarchyUnit(String path) {
+               LdapName dn = pathToName(path);
+               return directoryDao.doGetHierarchyUnit(dn);
+       }
+
+       @Override
+       public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
+               return directoryDao.doGetDirectHierarchyUnits(baseDn, functionalOnly);
+       }
+
+       @Override
+       public HierarchyUnit getDirectChild(Type type) {
+               // TODO factorise with hierarchy unit?
+               return switch (type) {
+               case ROLES -> getDirectoryDao().doGetHierarchyUnit((LdapName) getBaseDn().add(getSystemRoleBaseRdn()));
+               case PEOPLE -> getDirectoryDao().doGetHierarchyUnit((LdapName) getBaseDn().add(getUserBaseRdn()));
+               case GROUPS -> getDirectoryDao().doGetHierarchyUnit((LdapName) getBaseDn().add(getGroupBaseRdn()));
+               case FUNCTIONAL -> throw new IllegalArgumentException("Type must be a technical type");
+               };
+       }
+
+       @Override
+       public String getHierarchyUnitName() {
+               return getName();
+       }
+
+       @Override
+       public String getHierarchyUnitLabel(Locale locale) {
+               String key = LdapNameUtils.getLastRdn(getBaseDn()).getType();
+               Object value = LdapEntry.getLocalized(asLdapEntry().getProperties(), key, locale);
+               if (value == null)
+                       value = getHierarchyUnitName();
+               assert value != null;
+               return value.toString();
+       }
+
+       @Override
+       public HierarchyUnit getParent() {
+               return null;
+       }
+
+       @Override
+       public boolean isType(Type type) {
+               return Type.FUNCTIONAL.equals(type);
+       }
+
+       @Override
+       public CmsDirectory getDirectory() {
+               return this;
+       }
+
+       @Override
+       public HierarchyUnit createHierarchyUnit(String path) {
+               checkEdit();
+               LdapEntryWorkingCopy wc = getWorkingCopy();
+               LdapName dn = pathToName(path);
+               if ((getDirectoryDao().entryExists(dn) && !wc.getDeletedData().containsKey(dn))
+                               || wc.getNewData().containsKey(dn))
+                       throw new IllegalArgumentException("Already a hierarchy unit " + path);
+               BasicAttributes attrs = new BasicAttributes(true);
+               attrs.put(LdapAttr.objectClass.name(), LdapObj.organizationalUnit.name());
+               Rdn nameRdn = dn.getRdn(dn.size() - 1);
+               // TODO deal with multiple attr RDN
+               attrs.put(nameRdn.getType(), nameRdn.getValue());
+               wc.getModifiedData().put(dn, attrs);
+               LdapHierarchyUnit newHierarchyUnit = new LdapHierarchyUnit(this, dn);
+               wc.getNewData().put(dn, newHierarchyUnit);
+               return newHierarchyUnit;
+       }
+
+       /*
+        * PATHS
+        */
+
+       @Override
+       public String getBase() {
+               return getBaseDn().toString();
+       }
+
+       @Override
+       public String getName() {
+               return nameToSimple(getBaseDn(), ".");
+       }
+
+       protected String nameToRelativePath(LdapName dn) {
+               LdapName name = LdapNameUtils.relativeName(getBaseDn(), dn);
+               return nameToSimple(name, "/");
+       }
+
+       protected String nameToSimple(LdapName name, String separator) {
+               StringJoiner path = new StringJoiner(separator);
+               for (int i = 0; i < name.size(); i++) {
+                       path.add(name.getRdn(i).getValue().toString());
+               }
+               return path.toString();
+
+       }
+
+       protected LdapName pathToName(String path) {
+               try {
+                       LdapName name = (LdapName) getBaseDn().clone();
+                       String[] segments = path.split("/");
+                       Rdn parentRdn = null;
+                       // segments[0] is the directory itself
+                       for (int i = 0; i < segments.length; i++) {
+                               String segment = segments[i];
+                               // TODO make attr names configurable ?
+                               String attr = getDirectory().getRealm().isPresent()/* IPA */ ? LdapAttr.cn.name() : LdapAttr.ou.name();
+                               if (parentRdn != null) {
+                                       if (getUserBaseRdn().equals(parentRdn))
+                                               attr = LdapAttr.uid.name();
+                                       else if (getGroupBaseRdn().equals(parentRdn))
+                                               attr = LdapAttr.cn.name();
+                                       else if (getSystemRoleBaseRdn().equals(parentRdn))
+                                               attr = LdapAttr.cn.name();
+                               }
+                               Rdn rdn = new Rdn(attr, segment);
+                               name.add(rdn);
+                               parentRdn = rdn;
+                       }
+                       return name;
+               } catch (InvalidNameException e) {
+                       throw new IllegalStateException("Cannot convert " + path + " to LDAP name", e);
+               }
+
+       }
+
+       /*
+        * UTILITIES
+        */
+       protected boolean isExternal(LdapName name) {
+               return !name.startsWith(baseDn);
+       }
+
+       protected static boolean hasObjectClass(Attributes attrs, LdapObj objectClass) {
+               return hasObjectClass(attrs, objectClass.name());
+       }
+
+       protected static boolean hasObjectClass(Attributes attrs, String objectClass) {
+               try {
+                       Attribute attr = attrs.get(LdapAttr.objectClass.name());
+                       NamingEnumeration<?> en = attr.getAll();
+                       while (en.hasMore()) {
+                               String v = en.next().toString();
+                               if (v.equalsIgnoreCase(objectClass))
+                                       return true;
+
+                       }
+                       return false;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot search for objectClass " + objectClass, e);
+               }
+       }
+
+       private static boolean readOnlyDefault(String uriStr) {
+               if (uriStr == null)
+                       return true;
+               /// TODO make it more generic
+               URI uri;
+               try {
+                       uri = new URI(uriStr.split(" ")[0]);
+               } catch (URISyntaxException e) {
+                       throw new IllegalArgumentException(e);
+               }
+               if (uri.getScheme() == null)
+                       return false;// assume relative file to be writable
+               if (uri.getScheme().equals(DirectoryConf.SCHEME_FILE)) {
+                       File file = new File(uri);
+                       if (file.exists())
+                               return !file.canWrite();
+                       else
+                               return !file.getParentFile().canWrite();
+               } else if (uri.getScheme().equals(DirectoryConf.SCHEME_LDAP)) {
+                       if (uri.getAuthority() != null)// assume writable if authenticated
+                               return false;
+               } else if (uri.getScheme().equals(DirectoryConf.SCHEME_OS)) {
+                       return true;
+               }
+               return true;// read only by default
+       }
+
+       /*
+        * AS AN ENTRY
+        */
+       public LdapEntry asLdapEntry() {
+               try {
+                       return directoryDao.doGetEntry(baseDn);
+               } catch (NameNotFoundException e) {
+                       throw new IllegalStateException("Cannot get " + baseDn + " entry", e);
+               }
+       }
+
+       public Dictionary<String, Object> getProperties() {
+               return asLdapEntry().getProperties();
+       }
+
+       /*
+        * ACCESSORS
+        */
+       @Override
+       public Optional<String> getRealm() {
+               Object realm = configProperties.get(DirectoryConf.realm.name());
+               if (realm == null)
+                       return Optional.empty();
+               return Optional.of(realm.toString());
+       }
+
+       public LdapName getBaseDn() {
+               return (LdapName) baseDn.clone();
+       }
+
+       public boolean isReadOnly() {
+               return readOnly;
+       }
+
+       public boolean isDisabled() {
+               return disabled;
+       }
+
+       public boolean isAuthenticated() {
+               return authenticated;
+       }
+
+       public Rdn getUserBaseRdn() {
+               return userBaseRdn;
+       }
+
+       public Rdn getGroupBaseRdn() {
+               return groupBaseRdn;
+       }
+
+       public Rdn getSystemRoleBaseRdn() {
+               return systemRoleBaseRdn;
+       }
+
+//     public Dictionary<String, Object> getConfigProperties() {
+//             return configProperties;
+//     }
+
+       public Dictionary<String, Object> cloneConfigProperties() {
+               return new Hashtable<>(configProperties);
+       }
+
+       public String getForcedPassword() {
+               return forcedPassword;
+       }
+
+       public boolean isScoped() {
+               return scoped;
+       }
+
+       public List<String> getCredentialAttributeIds() {
+               return credentialAttributeIds;
+       }
+
+       public String getUri() {
+               return uri;
+       }
+
+       public LdapDirectoryDao getDirectoryDao() {
+               return directoryDao;
+       }
+
+       /** dn can be null, in that case a default should be returned. */
+       public String getUserObjectClass() {
+               return userObjectClass;
+       }
+
+       public String getGroupObjectClass() {
+               return groupObjectClass;
+       }
+
+       public String getMemberAttributeId() {
+               return memberAttributeId;
+       }
+
+       /*
+        * OBJECT METHODS
+        */
+
+       @Override
+       public int hashCode() {
+               return baseDn.hashCode();
+       }
+
+       @Override
+       public String toString() {
+               return "Directory " + baseDn.toString();
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectoryDao.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectoryDao.java
new file mode 100644 (file)
index 0000000..c4a6910
--- /dev/null
@@ -0,0 +1,33 @@
+package org.argeo.cms.directory.ldap;
+
+import javax.naming.ldap.LdapName;
+
+/** Base class for LDAP/LDIF directory DAOs. */
+public abstract class AbstractLdapDirectoryDao implements LdapDirectoryDao {
+
+       private AbstractLdapDirectory directory;
+
+       public AbstractLdapDirectoryDao(AbstractLdapDirectory directory) {
+               this.directory = directory;
+       }
+
+       public AbstractLdapDirectory getDirectory() {
+               return directory;
+       }
+
+       @Override
+       public LdapEntryWorkingCopy newWorkingCopy() {
+               return new LdapEntryWorkingCopy();
+       }
+
+       @Override
+       public LdapEntry newUser(LdapName name) {
+               return getDirectory().newUser(name);
+       }
+
+       @Override
+       public LdapEntry newGroup(LdapName name) {
+               return getDirectory().newGroup(name);
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/AttributesDictionary.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/AttributesDictionary.java
new file mode 100644 (file)
index 0000000..9deda1b
--- /dev/null
@@ -0,0 +1,171 @@
+package org.argeo.cms.directory.ldap;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+
+public class AttributesDictionary extends Dictionary<String, Object> {
+       private final Attributes attributes;
+
+       /** The provided attributes is wrapped, not copied. */
+       public AttributesDictionary(Attributes attributes) {
+               if (attributes == null)
+                       throw new IllegalArgumentException("Attributes cannot be null");
+               this.attributes = attributes;
+       }
+
+       @Override
+       public int size() {
+               return attributes.size();
+       }
+
+       @Override
+       public boolean isEmpty() {
+               return attributes.size() == 0;
+       }
+
+       @Override
+       public Enumeration<String> keys() {
+               NamingEnumeration<String> namingEnumeration = attributes.getIDs();
+               return new Enumeration<String>() {
+
+                       @Override
+                       public boolean hasMoreElements() {
+                               return namingEnumeration.hasMoreElements();
+                       }
+
+                       @Override
+                       public String nextElement() {
+                               return namingEnumeration.nextElement();
+                       }
+
+               };
+       }
+
+       @Override
+       public Enumeration<Object> elements() {
+               NamingEnumeration<String> namingEnumeration = attributes.getIDs();
+               return new Enumeration<Object>() {
+
+                       @Override
+                       public boolean hasMoreElements() {
+                               return namingEnumeration.hasMoreElements();
+                       }
+
+                       @Override
+                       public Object nextElement() {
+                               String key = namingEnumeration.nextElement();
+                               return get(key);
+                       }
+
+               };
+       }
+
+       @Override
+       /** @returns a <code>String</code> or <code>String[]</code> */
+       public Object get(Object key) {
+               try {
+                       if (key == null)
+                               throw new IllegalArgumentException("Key cannot be null");
+                       Attribute attr = attributes.get(key.toString());
+                       if (attr == null)
+                               return null;
+                       if (attr.size() == 0)
+                               throw new IllegalStateException("There must be at least one value");
+                       else if (attr.size() == 1) {
+                               return attr.get().toString();
+                       } else {// multiple
+                               String[] res = new String[attr.size()];
+                               for (int i = 0; i < attr.size(); i++) {
+                                       Object value = attr.get();
+                                       if (value == null)
+                                               throw new RuntimeException("Values cannot be null");
+                                       res[i] = attr.get(i).toString();
+                               }
+                               return res;
+                       }
+               } catch (NamingException e) {
+                       throw new RuntimeException("Cannot get value for " + key, e);
+               }
+       }
+
+       @Override
+       public Object put(String key, Object value) {
+               if (key == null)
+                       throw new IllegalArgumentException("Key cannot be null");
+               if (value == null)
+                       throw new IllegalArgumentException("Value cannot be null");
+
+               Object oldValue = get(key);
+               Attribute attr = attributes.get(key);
+               if (attr == null) {
+                       attr = new BasicAttribute(key);
+                       attributes.put(attr);
+               }
+
+               if (value instanceof String[]) {
+                       String[] values = (String[]) value;
+                       // clean additional values
+                       for (int i = values.length; i < attr.size(); i++)
+                               attr.remove(i);
+                       // set values
+                       for (int i = 0; i < values.length; i++) {
+                               attr.set(i, values[i]);
+                       }
+               } else {
+                       if (attr.size() > 1)
+                               throw new IllegalArgumentException("Attribute " + key + " is multi-valued");
+                       if (attr.size() == 1) {
+                               try {
+                                       if (!attr.get(0).equals(value))
+                                               attr.set(0, value.toString());
+                               } catch (NamingException e) {
+                                       throw new RuntimeException("Cannot check existing value", e);
+                               }
+                       } else {
+                               attr.add(value.toString());
+                       }
+               }
+               return oldValue;
+       }
+
+       @Override
+       public Object remove(Object key) {
+               if (key == null)
+                       throw new IllegalArgumentException("Key cannot be null");
+               Object oldValue = get(key);
+               if (oldValue == null)
+                       return null;
+               return attributes.remove(key.toString());
+       }
+
+       /**
+        * Copy the <b>content</b> of an {@link Attributes} to the provided
+        * {@link Dictionary}.
+        */
+       public static void copy(Attributes attributes, Dictionary<String, Object> dictionary) {
+               AttributesDictionary ad = new AttributesDictionary(attributes);
+               Enumeration<String> keys = ad.keys();
+               while (keys.hasMoreElements()) {
+                       String key = keys.nextElement();
+                       dictionary.put(key, ad.get(key));
+               }
+       }
+
+       /**
+        * Copy a {@link Dictionary} into an {@link Attributes}.
+        */
+       public static void copy(Dictionary<String, Object> dictionary, Attributes attributes) {
+               AttributesDictionary ad = new AttributesDictionary(attributes);
+               Enumeration<String> keys = dictionary.keys();
+               while (keys.hasMoreElements()) {
+                       String key = keys.nextElement();
+                       ad.put(key, dictionary.get(key));
+               }
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/AuthPassword.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/AuthPassword.java
new file mode 100644 (file)
index 0000000..a871912
--- /dev/null
@@ -0,0 +1,140 @@
+package org.argeo.cms.directory.ldap;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.StringTokenizer;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+
+/** LDAP authPassword field according to RFC 3112 */
+public class AuthPassword implements CallbackHandler {
+       private final String authScheme;
+       private final String authInfo;
+       private final String authValue;
+
+       public AuthPassword(String value) {
+               StringTokenizer st = new StringTokenizer(value, "$");
+               // TODO make it more robust, deal with bad formatting
+               this.authScheme = st.nextToken().trim();
+               this.authInfo = st.nextToken().trim();
+               this.authValue = st.nextToken().trim();
+
+               String expectedAuthScheme = getExpectedAuthScheme();
+               if (expectedAuthScheme != null && !authScheme.equals(expectedAuthScheme))
+                       throw new IllegalArgumentException(
+                                       "Auth scheme " + authScheme + " is not compatible with " + expectedAuthScheme);
+       }
+
+       protected AuthPassword(String authInfo, String authValue) {
+               this.authScheme = getExpectedAuthScheme();
+               if (authScheme == null)
+                       throw new IllegalArgumentException("Expected auth scheme cannot be null");
+               this.authInfo = authInfo;
+               this.authValue = authValue;
+       }
+
+       protected AuthPassword(AuthPassword authPassword) {
+               this.authScheme = authPassword.getAuthScheme();
+               this.authInfo = authPassword.getAuthInfo();
+               this.authValue = authPassword.getAuthValue();
+       }
+
+       protected String getExpectedAuthScheme() {
+               return null;
+       }
+
+       protected boolean matchAuthValue(Object object) {
+               return authValue.equals(object.toString());
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof AuthPassword))
+                       return false;
+               AuthPassword authPassword = (AuthPassword) obj;
+               return authScheme.equals(authPassword.authScheme) && authInfo.equals(authPassword.authInfo)
+                               && authValue.equals(authValue);
+       }
+
+       public boolean keyEquals(AuthPassword authPassword) {
+               return authScheme.equals(authPassword.authScheme) && authInfo.equals(authPassword.authInfo);
+       }
+
+       @Override
+       public int hashCode() {
+               return authValue.hashCode();
+       }
+
+       @Override
+       public String toString() {
+               return toAuthPassword();
+       }
+
+       public final String toAuthPassword() {
+               return getAuthScheme() + '$' + authInfo + '$' + authValue;
+       }
+
+       public String getAuthScheme() {
+               return authScheme;
+       }
+
+       public String getAuthInfo() {
+               return authInfo;
+       }
+
+       public String getAuthValue() {
+               return authValue;
+       }
+
+       public static AuthPassword matchAuthValue(Attributes attributes, char[] value) {
+               try {
+                       Attribute authPassword = attributes.get(LdapAttr.authPassword.name());
+                       if (authPassword != null) {
+                               NamingEnumeration<?> values = authPassword.getAll();
+                               while (values.hasMore()) {
+                                       Object val = values.next();
+                                       AuthPassword token = new AuthPassword(val.toString());
+                                       String auth;
+                                       if (Arrays.binarySearch(value, '$') >= 0) {
+                                               auth = token.authInfo + '$' + token.authValue;
+                                       } else {
+                                               auth = token.authValue;
+                                       }
+                                       if (Arrays.equals(auth.toCharArray(), value))
+                                               return token;
+                                       // if (token.matchAuthValue(value))
+                                       // return token;
+                               }
+                       }
+                       return null;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot check attribute", e);
+               }
+       }
+
+       public static boolean remove(Attributes attributes, AuthPassword value) {
+               Attribute authPassword = attributes.get(LdapAttr.authPassword.name());
+               return authPassword.remove(value.toAuthPassword());
+       }
+
+       @Override
+       public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+               for (Callback callback : callbacks) {
+                       if (callback instanceof NameCallback)
+                               ((NameCallback) callback).setName(toAuthPassword());
+                       else if (callback instanceof PasswordCallback)
+                               ((PasswordCallback) callback).setPassword(getAuthValue().toCharArray());
+               }
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/DefaultLdapEntry.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/DefaultLdapEntry.java
new file mode 100644 (file)
index 0000000..94e0ac4
--- /dev/null
@@ -0,0 +1,482 @@
+package org.argeo.cms.directory.ldap;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.acr.ldap.LdapObj;
+import org.argeo.api.cms.directory.DirectoryDigestUtils;
+
+/** An entry in an LDAP (or LDIF) directory. */
+public class DefaultLdapEntry implements LdapEntry {
+       private final AbstractLdapDirectory directory;
+
+       private final LdapName dn;
+
+       private AttributeDictionary properties;
+       private AttributeDictionary credentials;
+
+//     private String primaryObjectClass;
+//     private List<String> objectClasses = new ArrayList<>();
+
+       protected DefaultLdapEntry(AbstractLdapDirectory directory, LdapName dn) {
+               Objects.requireNonNull(directory);
+               Objects.requireNonNull(dn);
+               this.directory = directory;
+               this.dn = dn;
+
+               // Object classes
+//             Objects.requireNonNull(initialAttributes);
+//             try {
+//                     NamingEnumeration<?> en = initialAttributes.get(LdapAttrs.objectClass.name()).getAll();
+//                     String first = null;
+//                     attrs: while (en.hasMore()) {
+//                             String v = en.next().toString();
+//                             if (v.equalsIgnoreCase(LdapObjs.top.name()))
+//                                     continue attrs;
+//                             if (first == null)
+//                                     first = v;
+//                             if (v.equalsIgnoreCase(getDirectory().getUserObjectClass()))
+//                                     primaryObjectClass = getDirectory().getUserObjectClass();
+//                             else if (v.equalsIgnoreCase(getDirectory().getGroupObjectClass()))
+//                                     primaryObjectClass = getDirectory().getGroupObjectClass();
+//                             objectClasses.add(v);
+//                     }
+//                     if (primaryObjectClass == null) {
+//                             if (first == null)
+//                                     throw new IllegalStateException("Could not find primary object class");
+//                             primaryObjectClass = first;
+//                     }
+//             } catch (NamingException e) {
+//                     throw new IllegalStateException("Cannot find object classes", e);
+//             }
+
+       }
+
+       @Override
+       public LdapName getDn() {
+               // always return a copy since LdapName is mutable
+               return (LdapName) dn.clone();
+       }
+
+       public synchronized Attributes getAttributes() {
+               return isEditing() ? getModifiedAttributes() : getDirectory().getDirectoryDao().doGetAttributes(dn);
+       }
+
+       @Override
+       public List<LdapName> getReferences(String attributeId) {
+               Attribute memberAttribute = getAttributes().get(attributeId);
+               if (memberAttribute == null)
+                       return new ArrayList<LdapName>();
+               try {
+                       List<LdapName> roles = new ArrayList<LdapName>();
+                       NamingEnumeration<?> values = memberAttribute.getAll();
+                       while (values.hasMore()) {
+                               LdapName dn = new LdapName(values.next().toString());
+                               roles.add(dn);
+                       }
+                       return roles;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get members", e);
+               }
+
+       }
+
+       /** Should only be called from working copy thread. */
+       protected synchronized Attributes getModifiedAttributes() {
+               assert getWc() != null;
+               return getWc().getModifiedData().get(getDn());
+       }
+
+       protected synchronized boolean isEditing() {
+               return getWc() != null && getModifiedAttributes() != null;
+       }
+
+       private synchronized LdapEntryWorkingCopy getWc() {
+               return directory.getWorkingCopy();
+       }
+
+       protected synchronized void startEditing() {
+//             if (frozen)
+//                     throw new IllegalStateException("Cannot edit frozen view");
+               if (directory.isReadOnly())
+                       throw new IllegalStateException("User directory is read-only");
+               assert getModifiedAttributes() == null;
+               getWc().startEditing(this);
+               // modifiedAttributes = (Attributes) publishedAttributes.clone();
+       }
+
+       public synchronized void publishAttributes(Attributes modifiedAttributes) {
+//             publishedAttributes = modifiedAttributes;
+       }
+
+       /*
+        * PROPERTIES
+        */
+       @Override
+       public Dictionary<String, Object> getProperties() {
+               if (properties == null)
+                       properties = new AttributeDictionary(false);
+               return properties;
+       }
+
+       public Dictionary<String, Object> getCredentials() {
+               if (credentials == null)
+                       credentials = new AttributeDictionary(true);
+               return credentials;
+       }
+
+       /*
+        * CREDENTIALS
+        */
+       @Override
+       public boolean hasCredential(String key, Object value) {
+               if (key == null) {
+                       // TODO check other sources (like PKCS12)
+                       // String pwd = new String((char[]) value);
+                       // authPassword (RFC 312 https://tools.ietf.org/html/rfc3112)
+                       char[] password = DirectoryDigestUtils.bytesToChars(value);
+
+                       if (getDirectory().getForcedPassword() != null
+                                       && getDirectory().getForcedPassword().equals(new String(password)))
+                               return true;
+
+                       AuthPassword authPassword = AuthPassword.matchAuthValue(getAttributes(), password);
+                       if (authPassword != null) {
+                               if (authPassword.getAuthScheme().equals(SharedSecret.X_SHARED_SECRET)) {
+                                       SharedSecret onceToken = new SharedSecret(authPassword);
+                                       if (onceToken.isExpired()) {
+                                               // AuthPassword.remove(getAttributes(), onceToken);
+                                               return false;
+                                       } else {
+                                               // boolean wasRemoved = AuthPassword.remove(getAttributes(), onceToken);
+                                               return true;
+                                       }
+                                       // TODO delete expired tokens?
+                               } else {
+                                       // TODO implement SHA
+                                       throw new UnsupportedOperationException(
+                                                       "Unsupported authPassword scheme " + authPassword.getAuthScheme());
+                               }
+                       }
+
+                       // Regular password
+//                     byte[] hashedPassword = hash(password, DigestUtils.PASSWORD_SCHEME_PBKDF2_SHA256);
+                       if (hasCredential(LdapAttr.userPassword.name(), DirectoryDigestUtils.charsToBytes(password)))
+                               return true;
+                       return false;
+               }
+
+               Object storedValue = getCredentials().get(key);
+               if (storedValue == null || value == null)
+                       return false;
+               if (!(value instanceof String || value instanceof byte[]))
+                       return false;
+               if (storedValue instanceof String && value instanceof String)
+                       return storedValue.equals(value);
+               if (storedValue instanceof byte[] && value instanceof byte[]) {
+                       String storedBase64 = new String((byte[]) storedValue, US_ASCII);
+                       String passwordScheme = null;
+                       if (storedBase64.charAt(0) == '{') {
+                               int index = storedBase64.indexOf('}');
+                               if (index > 0) {
+                                       passwordScheme = storedBase64.substring(1, index);
+                                       String storedValueBase64 = storedBase64.substring(index + 1);
+                                       byte[] storedValueBytes = Base64.getDecoder().decode(storedValueBase64);
+                                       char[] passwordValue = DirectoryDigestUtils.bytesToChars((byte[]) value);
+                                       byte[] valueBytes;
+                                       if (DirectoryDigestUtils.PASSWORD_SCHEME_SHA.equals(passwordScheme)) {
+                                               valueBytes = DirectoryDigestUtils.toPasswordScheme(passwordScheme, passwordValue, null, null,
+                                                               null);
+                                       } else if (DirectoryDigestUtils.PASSWORD_SCHEME_PBKDF2_SHA256.equals(passwordScheme)) {
+                                               // see https://www.thesubtlety.com/post/a-389-ds-pbkdf2-password-checker/
+                                               byte[] iterationsArr = Arrays.copyOfRange(storedValueBytes, 0, 4);
+                                               BigInteger iterations = new BigInteger(iterationsArr);
+                                               byte[] salt = Arrays.copyOfRange(storedValueBytes, iterationsArr.length,
+                                                               iterationsArr.length + 64);
+                                               byte[] keyArr = Arrays.copyOfRange(storedValueBytes, iterationsArr.length + salt.length,
+                                                               storedValueBytes.length);
+                                               int keyLengthBits = keyArr.length * 8;
+                                               valueBytes = DirectoryDigestUtils.toPasswordScheme(passwordScheme, passwordValue, salt,
+                                                               iterations.intValue(), keyLengthBits);
+                                       } else {
+                                               throw new UnsupportedOperationException("Unknown password scheme " + passwordScheme);
+                                       }
+                                       return Arrays.equals(storedValueBytes, valueBytes);
+                               }
+                       }
+               }
+//             if (storedValue instanceof byte[] && value instanceof byte[]) {
+//                     return Arrays.equals((byte[]) storedValue, (byte[]) value);
+//             }
+               return false;
+       }
+
+       /** Hash the password */
+       private static byte[] sha1hash(char[] password) {
+               byte[] hashedPassword = ("{SHA}" + Base64.getEncoder()
+                               .encodeToString(DirectoryDigestUtils.sha1(DirectoryDigestUtils.charsToBytes(password))))
+                               .getBytes(StandardCharsets.UTF_8);
+               return hashedPassword;
+       }
+
+       public AbstractLdapDirectory getDirectory() {
+               return directory;
+       }
+
+       public LdapDirectoryDao getDirectoryDao() {
+               return directory.getDirectoryDao();
+       }
+
+       @Override
+       public int hashCode() {
+               return dn.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj instanceof LdapEntry) {
+                       LdapEntry that = (LdapEntry) obj;
+                       return this.dn.equals(that.getDn());
+               }
+               return false;
+       }
+
+       @Override
+       public String toString() {
+               return dn.toString();
+       }
+
+       private static boolean isAsciiPrintable(String str) {
+               if (str == null) {
+                       return false;
+               }
+               int sz = str.length();
+               for (int i = 0; i < sz; i++) {
+                       if (isAsciiPrintable(str.charAt(i)) == false) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       private static boolean isAsciiPrintable(char ch) {
+               return ch >= 32 && ch < 127;
+       }
+
+       protected class AttributeDictionary extends Dictionary<String, Object> {
+               private final List<String> effectiveKeys = new ArrayList<String>();
+               private final List<String> attrFilter;
+               private final Boolean includeFilter;
+
+               public AttributeDictionary(Boolean credentials) {
+                       this.attrFilter = getDirectory().getCredentialAttributeIds();
+                       this.includeFilter = credentials;
+                       try {
+                               NamingEnumeration<String> ids = getAttributes().getIDs();
+                               while (ids.hasMore()) {
+                                       String id = ids.next();
+                                       if (credentials && attrFilter.contains(id))
+                                               effectiveKeys.add(id);
+                                       else if (!credentials && !attrFilter.contains(id))
+                                               effectiveKeys.add(id);
+                               }
+                       } catch (NamingException e) {
+                               throw new IllegalStateException("Cannot initialise attribute dictionary", e);
+                       }
+                       if (!credentials)
+                               effectiveKeys.add(LdapAttr.objectClasses.name());
+               }
+
+               @Override
+               public int size() {
+                       return effectiveKeys.size();
+               }
+
+               @Override
+               public boolean isEmpty() {
+                       return effectiveKeys.size() == 0;
+               }
+
+               @Override
+               public Enumeration<String> keys() {
+                       return Collections.enumeration(effectiveKeys);
+               }
+
+               @Override
+               public Enumeration<Object> elements() {
+                       final Iterator<String> it = effectiveKeys.iterator();
+                       return new Enumeration<Object>() {
+
+                               @Override
+                               public boolean hasMoreElements() {
+                                       return it.hasNext();
+                               }
+
+                               @Override
+                               public Object nextElement() {
+                                       String key = it.next();
+                                       return get(key);
+                               }
+
+                       };
+               }
+
+               @Override
+               public Object get(Object key) {
+                       try {
+                               Attribute attr = !key.equals(LdapAttr.objectClasses.name()) ? getAttributes().get(key.toString())
+                                               : getAttributes().get(LdapAttr.objectClass.name());
+                               if (attr == null)
+                                       return null;
+                               Object value = attr.get();
+                               if (value instanceof byte[]) {
+                                       if (key.equals(LdapAttr.userPassword.name()))
+                                               // TODO other cases (certificates, images)
+                                               return value;
+                                       value = new String((byte[]) value, StandardCharsets.UTF_8);
+                               }
+                               if (attr.size() == 1)
+                                       return value;
+                               // special case for object class
+                               if (key.equals(LdapAttr.objectClass.name())) {
+                                       // TODO support multiple object classes
+                                       NamingEnumeration<?> en = attr.getAll();
+                                       String first = null;
+                                       attrs: while (en.hasMore()) {
+                                               String v = en.next().toString();
+                                               if (v.equalsIgnoreCase(LdapObj.top.name()))
+                                                       continue attrs;
+                                               if (first == null)
+                                                       first = v;
+                                               if (v.equalsIgnoreCase(getDirectory().getUserObjectClass()))
+                                                       return getDirectory().getUserObjectClass();
+                                               else if (v.equalsIgnoreCase(getDirectory().getGroupObjectClass()))
+                                                       return getDirectory().getGroupObjectClass();
+                                       }
+                                       if (first != null)
+                                               return first;
+                                       throw new IllegalStateException("Cannot find objectClass in " + value);
+                               } else {
+                                       NamingEnumeration<?> en = attr.getAll();
+                                       StringJoiner values = new StringJoiner("\n");
+                                       while (en.hasMore()) {
+                                               String v = en.next().toString();
+                                               values.add(v);
+                                       }
+                                       return values.toString();
+                               }
+//                             else
+//                                     return value;
+                       } catch (NamingException e) {
+                               throw new IllegalStateException("Cannot get value for attribute " + key, e);
+                       }
+               }
+
+               @Override
+               public Object put(String key, Object value) {
+                       Objects.requireNonNull(value, "Value for key " + key + " is null");
+                       try {
+                               if (key == null) {
+                                       // FIXME remove this "feature", a key should be specified
+                                       // TODO persist to other sources (like PKCS12)
+                                       char[] password = DirectoryDigestUtils.bytesToChars(value);
+                                       byte[] hashedPassword = sha1hash(password);
+                                       return put(LdapAttr.userPassword.name(), hashedPassword);
+                               }
+                               if (key.startsWith("X-")) {
+                                       return put(LdapAttr.authPassword.name(), value);
+                               }
+
+                               // start editing
+                               getDirectory().checkEdit();
+                               if (!isEditing())
+                                       startEditing();
+
+                               // object classes special case.
+                               if (key.equals(LdapAttr.objectClasses.name())) {
+                                       Attribute attribute = new BasicAttribute(LdapAttr.objectClass.name());
+                                       String[] objectClasses = value.toString().split("\n");
+                                       for (String objectClass : objectClasses) {
+                                               if (objectClass.trim().equals(""))
+                                                       continue;
+                                               attribute.add(objectClass);
+                                       }
+                                       Attribute previousAttribute = getModifiedAttributes().put(attribute);
+                                       if (previousAttribute != null)
+                                               return previousAttribute.get();
+                                       else
+                                               return null;
+                               }
+
+                               if (!(value instanceof String || value instanceof byte[]))
+                                       throw new IllegalArgumentException("Value must be String or byte[]");
+
+                               if (includeFilter && !attrFilter.contains(key))
+                                       throw new IllegalArgumentException("Key " + key + " not included");
+                               else if (!includeFilter && attrFilter.contains(key))
+                                       throw new IllegalArgumentException("Key " + key + " excluded");
+
+                               Attribute attribute = getModifiedAttributes().get(key.toString());
+                               // if (attribute == null) // block unit tests
+                               attribute = new BasicAttribute(key.toString());
+                               if (value instanceof String && !isAsciiPrintable(((String) value)))
+                                       attribute.add(((String) value).getBytes(StandardCharsets.UTF_8));
+                               else
+                                       attribute.add(value);
+                               Attribute previousAttribute = getModifiedAttributes().put(attribute);
+                               if (previousAttribute != null)
+                                       return previousAttribute.get();
+                               else
+                                       return null;
+                       } catch (NamingException e) {
+                               throw new IllegalStateException("Cannot get value for attribute " + key, e);
+                       }
+               }
+
+               @Override
+               public Object remove(Object key) {
+                       getDirectory().checkEdit();
+                       if (!isEditing())
+                               startEditing();
+
+                       if (includeFilter && !attrFilter.contains(key))
+                               throw new IllegalArgumentException("Key " + key + " not included");
+                       else if (!includeFilter && attrFilter.contains(key))
+                               throw new IllegalArgumentException("Key " + key + " excluded");
+
+                       try {
+                               Attribute attr = getModifiedAttributes().remove(key.toString());
+                               if (attr != null)
+                                       return attr.get();
+                               else
+                                       return null;
+                       } catch (NamingException e) {
+                               throw new IllegalStateException("Cannot remove attribute " + key, e);
+                       }
+               }
+
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/IpaUtils.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/IpaUtils.java
new file mode 100644 (file)
index 0000000..b14c090
--- /dev/null
@@ -0,0 +1,150 @@
+package org.argeo.cms.directory.ldap;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.StringJoiner;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.cms.dns.DnsBrowser;
+import org.argeo.cms.runtime.DirectoryConf;
+
+/** Free IPA specific conventions. */
+public class IpaUtils {
+       public final static String IPA_USER_BASE = "cn=users";
+       public final static String IPA_GROUP_BASE = "cn=groups";
+       public final static String IPA_ROLE_BASE = "cn=roles";
+       public final static String IPA_SERVICE_BASE = "cn=services";
+
+       public final static String IPA_ACCOUNTS_BASE = "cn=accounts";
+
+       private final static String KRB_PRINCIPAL_NAME = LdapAttr.krbPrincipalName.name().toLowerCase();
+
+       public final static String IPA_USER_DIRECTORY_CONFIG = DirectoryConf.userBase + "=" + IPA_USER_BASE + "&"
+                       + DirectoryConf.groupBase + "=" + IPA_GROUP_BASE + "&" + DirectoryConf.systemRoleBase + "=" + IPA_ROLE_BASE
+                       + "&" + DirectoryConf.readOnly + "=true";
+
+       @Deprecated
+       static String domainToUserDirectoryConfigPath(String realm) {
+               return domainToBaseDn(realm) + "?" + IPA_USER_DIRECTORY_CONFIG + "&" + DirectoryConf.realm.name() + "=" + realm;
+       }
+
+       public static void addIpaConfig(String realm, Dictionary<String, Object> properties) {
+               properties.put(DirectoryConf.baseDn.name(), domainToBaseDn(realm));
+               properties.put(DirectoryConf.realm.name(), realm);
+               properties.put(DirectoryConf.userBase.name(), IPA_USER_BASE);
+               properties.put(DirectoryConf.groupBase.name(), IPA_GROUP_BASE);
+               properties.put(DirectoryConf.systemRoleBase.name(), IPA_ROLE_BASE);
+               properties.put(DirectoryConf.readOnly.name(), Boolean.TRUE.toString());
+       }
+
+       public static String domainToBaseDn(String domain) {
+               String[] dcs = domain.split("\\.");
+               StringJoiner sj = new StringJoiner(",");
+               for (int i = 0; i < dcs.length; i++) {
+                       String dc = dcs[i];
+                       sj.add(LdapAttr.dc.name() + '=' + dc.toLowerCase());
+               }
+               return IPA_ACCOUNTS_BASE + ',' + sj.toString();
+       }
+
+       public static LdapName kerberosToDn(String kerberosName) {
+               String[] kname = kerberosName.split("@");
+               String username = kname[0];
+               String baseDn = domainToBaseDn(kname[1]);
+               String dn;
+               if (!username.contains("/"))
+                       dn = LdapAttr.uid + "=" + username + "," + IPA_USER_BASE + "," + baseDn;
+               else
+                       dn = KRB_PRINCIPAL_NAME + "=" + kerberosName + "," + IPA_SERVICE_BASE + "," + baseDn;
+               try {
+                       return new LdapName(dn);
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Badly formatted name for " + kerberosName + ": " + dn);
+               }
+       }
+
+       private IpaUtils() {
+
+       }
+
+       public static String kerberosDomainFromDns() {
+               String kerberosDomain;
+               try (DnsBrowser dnsBrowser = new DnsBrowser()) {
+                       // TODO retrieve hostname from CMS config
+                       InetAddress localhost = InetAddress.getLocalHost();
+                       String hostname = localhost.getHostName();
+                       int dotIndex = hostname.indexOf('.');
+                       if (dotIndex <= 0) {
+                               hostname = localhost.getCanonicalHostName();
+                               dotIndex = hostname.indexOf('.');
+                               if (dotIndex <= 0)
+                                       throw new IllegalArgumentException(
+                                                       "Cannot extract DNS zone from hostname " + hostname + " (" + localhost + ")");
+                       }
+                       String dnsZone = hostname.substring(dotIndex + 1);
+                       kerberosDomain = dnsBrowser.getRecord("_kerberos." + dnsZone, "TXT");
+                       return kerberosDomain;
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot determine Kerberos domain from DNS", e);
+               }
+
+       }
+
+       public static Dictionary<String, Object> convertIpaUri(URI uri) {
+               String path = uri.getPath();
+               String kerberosRealm;
+               if (path == null || path.length() <= 1) {
+                       kerberosRealm = kerberosDomainFromDns();
+               } else {
+                       kerberosRealm = path.substring(1);
+               }
+
+               if (kerberosRealm == null)
+                       throw new IllegalStateException("No Kerberos domain available for " + uri);
+               // TODO intergrate CA certificate in truststore
+               // String schemeToUse = SCHEME_LDAPS;
+               String schemeToUse = DirectoryConf.SCHEME_LDAP;
+               List<String> ldapHosts;
+               String ldapHostsStr = uri.getHost();
+               if (ldapHostsStr == null || ldapHostsStr.trim().equals("")) {
+                       try (DnsBrowser dnsBrowser = new DnsBrowser()) {
+                               ldapHosts = dnsBrowser.getSrvRecordsAsHosts("_ldap._tcp." + kerberosRealm.toLowerCase(),
+                                               schemeToUse.equals(DirectoryConf.SCHEME_LDAP) ? true : false);
+                               if (ldapHosts == null || ldapHosts.size() == 0) {
+                                       throw new IllegalStateException("Cannot configure LDAP for IPA " + uri);
+                               } else {
+                                       ldapHostsStr = ldapHosts.get(0);
+                               }
+                       } catch (IOException e) {
+                               throw new IllegalStateException("Cannot convert IPA uri " + uri, e);
+                       }
+               } else {
+                       ldapHosts = new ArrayList<>();
+                       ldapHosts.add(ldapHostsStr);
+               }
+
+               StringBuilder uriStr = new StringBuilder();
+               try {
+                       for (String host : ldapHosts) {
+                               URI convertedUri = new URI(schemeToUse + "://" + host + "/");
+                               uriStr.append(convertedUri).append(' ');
+                       }
+               } catch (URISyntaxException e) {
+                       throw new IllegalStateException("Cannot convert IPA uri " + uri, e);
+               }
+
+               Hashtable<String, Object> res = new Hashtable<>();
+               res.put(DirectoryConf.uri.name(), uriStr.toString());
+               addIpaConfig(kerberosRealm, res);
+               return res;
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapConnection.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapConnection.java
new file mode 100644 (file)
index 0000000..efc8cbc
--- /dev/null
@@ -0,0 +1,162 @@
+package org.argeo.cms.directory.ldap;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.cms.transaction.WorkingCopy;
+
+/** A synchronized wrapper for a single {@link InitialLdapContext}. */
+// TODO implement multiple contexts and connection pooling.
+public class LdapConnection {
+       private InitialLdapContext initialLdapContext = null;
+
+       public LdapConnection(String url, Dictionary<String, ?> properties) {
+               try {
+                       Hashtable<String, Object> connEnv = new Hashtable<String, Object>();
+                       connEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+                       connEnv.put(Context.PROVIDER_URL, url);
+                       connEnv.put("java.naming.ldap.attributes.binary", LdapAttr.userPassword.name());
+                       // use pooling in order to avoid connection timeout
+//                     connEnv.put("com.sun.jndi.ldap.connect.pool", "true");
+//                     connEnv.put("com.sun.jndi.ldap.connect.pool.timeout", 300000);
+
+                       initialLdapContext = new InitialLdapContext(connEnv, null);
+                       // StartTlsResponse tls = (StartTlsResponse) ctx
+                       // .extendedOperation(new StartTlsRequest());
+                       // tls.negotiate();
+                       Object securityAuthentication = properties.get(Context.SECURITY_AUTHENTICATION);
+                       if (securityAuthentication != null)
+                               initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, securityAuthentication);
+                       else
+                               initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
+                       Object principal = properties.get(Context.SECURITY_PRINCIPAL);
+                       if (principal != null) {
+                               initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, principal.toString());
+                               Object creds = properties.get(Context.SECURITY_CREDENTIALS);
+                               if (creds != null) {
+                                       initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, creds.toString());
+                               }
+                       }
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot connect to LDAP", e);
+               }
+
+       }
+
+       public void init() {
+
+       }
+
+       public void destroy() {
+               try {
+                       // tls.close();
+                       initialLdapContext.close();
+                       initialLdapContext = null;
+               } catch (NamingException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       protected InitialLdapContext getLdapContext() {
+               return initialLdapContext;
+       }
+
+       protected void reconnect() throws NamingException {
+               initialLdapContext.reconnect(initialLdapContext.getConnectControls());
+       }
+
+       public synchronized NamingEnumeration<SearchResult> search(LdapName searchBase, String searchFilter,
+                       SearchControls searchControls) throws NamingException {
+               NamingEnumeration<SearchResult> results;
+               try {
+                       results = getLdapContext().search(searchBase, searchFilter, searchControls);
+               } catch (CommunicationException e) {
+                       reconnect();
+                       results = getLdapContext().search(searchBase, searchFilter, searchControls);
+               }
+               return results;
+       }
+
+       public synchronized Attributes getAttributes(LdapName name) throws NamingException {
+               try {
+                       return getLdapContext().getAttributes(name);
+               } catch (CommunicationException e) {
+                       reconnect();
+                       return getLdapContext().getAttributes(name);
+               }
+       }
+
+       public synchronized boolean entryExists(LdapName name) throws NamingException {
+               String[] noAttrOID = new String[] { "1.1" };
+               try {
+                       getLdapContext().getAttributes(name, noAttrOID);
+                       return true;
+               } catch (CommunicationException e) {
+                       reconnect();
+                       getLdapContext().getAttributes(name, noAttrOID);
+                       return true;
+               } catch (NameNotFoundException e) {
+                       return false;
+               }
+       }
+
+       public synchronized void prepareChanges(WorkingCopy<?, ?, LdapName> wc) throws NamingException {
+               // make sure connection will work
+               reconnect();
+
+               // delete
+               for (LdapName dn : wc.getDeletedData().keySet()) {
+                       if (!entryExists(dn))
+                               throw new IllegalStateException("User to delete no found " + dn);
+               }
+               // add
+               for (LdapName dn : wc.getNewData().keySet()) {
+                       if (entryExists(dn))
+                               throw new IllegalStateException("User to create found " + dn);
+               }
+               // modify
+               for (LdapName dn : wc.getModifiedData().keySet()) {
+                       if (!wc.getNewData().containsKey(dn) && !entryExists(dn))
+                               throw new IllegalStateException("User to modify not found " + dn);
+               }
+
+       }
+
+//     protected boolean entryExists(LdapName dn) throws NamingException {
+//             try {
+//                     return getAttributes(dn).size() != 0;
+//             } catch (NameNotFoundException e) {
+//                     return false;
+//             }
+//     }
+
+       public synchronized void commitChanges(LdapEntryWorkingCopy wc) throws NamingException {
+               // delete
+               for (LdapName dn : wc.getDeletedData().keySet()) {
+                       getLdapContext().destroySubcontext(dn);
+               }
+               // add
+               for (LdapName dn : wc.getNewData().keySet()) {
+                       LdapEntry user = wc.getNewData().get(dn);
+                       getLdapContext().createSubcontext(dn, user.getAttributes());
+               }
+               // modify
+               for (LdapName dn : wc.getModifiedData().keySet()) {
+                       Attributes modifiedAttrs = wc.getModifiedData().get(dn);
+                       getLdapContext().modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, modifiedAttrs);
+               }
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDao.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDao.java
new file mode 100644 (file)
index 0000000..cdc1c9f
--- /dev/null
@@ -0,0 +1,264 @@
+package org.argeo.cms.directory.ldap;
+
+import static org.argeo.api.acr.ldap.LdapAttr.objectClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.naming.AuthenticationNotSupportedException;
+import javax.naming.Binding;
+import javax.naming.InvalidNameException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.acr.ldap.LdapObj;
+import org.argeo.api.cms.directory.HierarchyUnit;
+
+/** A user admin based on a LDAP server. */
+public class LdapDao extends AbstractLdapDirectoryDao {
+       private LdapConnection ldapConnection;
+
+       public LdapDao(AbstractLdapDirectory directory) {
+               super(directory);
+       }
+
+       @Override
+       public void init() {
+               ldapConnection = new LdapConnection(getDirectory().getUri().toString(), getDirectory().cloneConfigProperties());
+       }
+
+       public void destroy() {
+               ldapConnection.destroy();
+       }
+
+       @Override
+       public boolean checkConnection() {
+               try {
+                       return ldapConnection.entryExists(getDirectory().getBaseDn());
+               } catch (NamingException e) {
+                       return false;
+               }
+       }
+
+       @Override
+       public boolean entryExists(LdapName dn) {
+               try {
+                       return ldapConnection.entryExists(dn);
+               } catch (NameNotFoundException e) {
+                       return false;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot check " + dn, e);
+               }
+       }
+
+       @Override
+       public LdapEntry doGetEntry(LdapName name) throws NameNotFoundException {
+//             if (!entryExists(name))
+//                     throw new NameNotFoundException(name + " was not found in " + getDirectory().getBaseDn());
+               try {
+                       Attributes attrs = ldapConnection.getAttributes(name);
+
+                       LdapEntry res;
+                       Rdn technicalRdn = LdapNameUtils.getParentRdn(name);
+                       if (getDirectory().getGroupBaseRdn().equals(technicalRdn)) {
+                               if (attrs.size() == 0) {// exists but not accessible
+                                       attrs = new BasicAttributes();
+                                       attrs.put(LdapAttr.objectClass.name(), LdapObj.top.name());
+                                       attrs.put(LdapAttr.objectClass.name(), getDirectory().getGroupObjectClass());
+                               }
+                               res = newGroup(name);
+                       } else if (getDirectory().getSystemRoleBaseRdn().equals(technicalRdn)) {
+                               if (attrs.size() == 0) {// exists but not accessible
+                                       attrs = new BasicAttributes();
+                                       attrs.put(LdapAttr.objectClass.name(), LdapObj.top.name());
+                                       attrs.put(LdapAttr.objectClass.name(), getDirectory().getGroupObjectClass());
+                               }
+                               res = newGroup(name);
+                       } else if (getDirectory().getUserBaseRdn().equals(technicalRdn)) {
+                               if (attrs.size() == 0) {// exists but not accessible
+                                       attrs = new BasicAttributes();
+                                       attrs.put(LdapAttr.objectClass.name(), LdapObj.top.name());
+                                       attrs.put(LdapAttr.objectClass.name(), getDirectory().getUserObjectClass());
+                               }
+                               res = newUser(name);
+                       } else {
+                               res = new DefaultLdapEntry(getDirectory(), name);
+                       }
+                       return res;
+               } catch (NameNotFoundException e) {
+                       throw e;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot retrieve entry " + name, e);
+               }
+       }
+
+       @Override
+       public Attributes doGetAttributes(LdapName name) {
+               try {
+                       Attributes attrs = ldapConnection.getAttributes(name);
+                       return attrs;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get attributes for " + name);
+               }
+       }
+
+       @Override
+       public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
+               ArrayList<LdapEntry> res = new ArrayList<>();
+               try {
+                       String searchFilter = f != null ? f.toString()
+                                       : "(|(" + objectClass.name() + "=" + getDirectory().getUserObjectClass() + ")(" + objectClass.name()
+                                                       + "=" + getDirectory().getGroupObjectClass() + "))";
+                       SearchControls searchControls = new SearchControls();
+                       // only attribute needed is objectClass
+                       searchControls.setReturningAttributes(new String[] { objectClass.name() });
+                       // FIXME make one level consistent with deep
+                       searchControls.setSearchScope(deep ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
+
+                       // LdapName searchBase = getBaseDn();
+                       NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
+
+                       results: while (results.hasMoreElements()) {
+                               SearchResult searchResult = results.next();
+                               Attributes attrs = searchResult.getAttributes();
+                               Attribute objectClassAttr = attrs.get(objectClass.name());
+                               LdapName dn = toDn(searchBase, searchResult);
+                               LdapEntry role;
+                               if (objectClassAttr.contains(getDirectory().getGroupObjectClass())
+                                               || objectClassAttr.contains(getDirectory().getGroupObjectClass().toLowerCase()))
+                                       role = newGroup(dn);
+                               else if (objectClassAttr.contains(getDirectory().getUserObjectClass())
+                                               || objectClassAttr.contains(getDirectory().getUserObjectClass().toLowerCase()))
+                                       role = newUser(dn);
+                               else {
+//                                     log.warn("Unsupported LDAP type for " + searchResult.getName());
+                                       continue results;
+                               }
+                               res.add(role);
+                       }
+                       return res;
+               } catch (AuthenticationNotSupportedException e) {
+                       // ignore (typically an unsupported anonymous bind)
+                       // TODO better logging
+                       return res;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get roles for filter " + f, e);
+               }
+       }
+
+       private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
+               return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
+       }
+
+       @Override
+       public List<LdapName> getDirectGroups(LdapName dn) {
+               List<LdapName> directGroups = new ArrayList<LdapName>();
+               try {
+                       String searchFilter = "(&(" + objectClass + "=" + getDirectory().getGroupObjectClass() + ")("
+                                       + getDirectory().getMemberAttributeId() + "=" + dn + "))";
+
+                       SearchControls searchControls = new SearchControls();
+                       searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+                       LdapName searchBase = getDirectory().getBaseDn();
+                       NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
+
+                       while (results.hasMoreElements()) {
+                               SearchResult searchResult = (SearchResult) results.nextElement();
+                               directGroups.add(toDn(searchBase, searchResult));
+                       }
+                       return directGroups;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot populate direct members of " + dn, e);
+               }
+       }
+
+       @Override
+       public void prepare(LdapEntryWorkingCopy wc) {
+               try {
+                       ldapConnection.prepareChanges(wc);
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot prepare LDAP", e);
+               }
+       }
+
+       @Override
+       public void commit(LdapEntryWorkingCopy wc) {
+               try {
+                       ldapConnection.commitChanges(wc);
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot commit LDAP", e);
+               }
+       }
+
+       @Override
+       public void rollback(LdapEntryWorkingCopy wc) {
+               // prepare not impacting
+       }
+
+       /*
+        * HIERARCHY
+        */
+
+       @Override
+       public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
+               List<HierarchyUnit> res = new ArrayList<>();
+               try {
+                       String structuralFilter = functionalOnly ? ""
+                                       : "(" + getDirectory().getUserBaseRdn() + ")(" + getDirectory().getGroupBaseRdn() + ")("
+                                                       + getDirectory().getSystemRoleBaseRdn() + ")";
+                       String searchFilter = "(|(" + objectClass + "=" + LdapObj.organizationalUnit.name() + ")(" + objectClass
+                                       + "=" + LdapObj.organization.name() + ")" + structuralFilter + ")";
+
+                       SearchControls searchControls = new SearchControls();
+                       searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+                       // no attributes needed
+                       searchControls.setReturningAttributes(new String[0]);
+
+                       NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
+
+                       while (results.hasMoreElements()) {
+                               SearchResult searchResult = (SearchResult) results.nextElement();
+                               LdapName dn = toDn(searchBase, searchResult);
+//                             Attributes attrs = searchResult.getAttributes();
+                               LdapHierarchyUnit hierarchyUnit = new LdapHierarchyUnit(getDirectory(), dn);
+                               if (functionalOnly) {
+                                       if (hierarchyUnit.isFunctional())
+                                               res.add(hierarchyUnit);
+                               } else {
+                                       res.add(hierarchyUnit);
+                               }
+                       }
+                       return res;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get direct hierarchy units ", e);
+               }
+       }
+
+       @Override
+       public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
+               try {
+                       if (getDirectory().getBaseDn().equals(dn))
+                               return getDirectory();
+                       if (!dn.startsWith(getDirectory().getBaseDn()))
+                               throw new IllegalArgumentException(dn + " does not start with base DN " + getDirectory().getBaseDn());
+                       if (!ldapConnection.entryExists(dn))
+                               return null;
+                       return new LdapHierarchyUnit(getDirectory(), dn);
+               } catch (NameNotFoundException e) {
+                       return null;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
+               }
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDirectoryDao.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDirectoryDao.java
new file mode 100644 (file)
index 0000000..03b03ea
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.cms.directory.ldap;
+
+import java.util.List;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.api.cms.transaction.WorkingCopyProcessor;
+
+/** Low-level access to an LDAP/LDIF directory. */
+public interface LdapDirectoryDao extends WorkingCopyProcessor<LdapEntryWorkingCopy> {
+       boolean checkConnection();
+
+       boolean entryExists(LdapName dn);
+
+       LdapEntry doGetEntry(LdapName name) throws NameNotFoundException;
+
+       Attributes doGetAttributes(LdapName name);
+
+       List<LdapEntry> doGetEntries(LdapName searchBase, String filter, boolean deep);
+
+       List<LdapName> getDirectGroups(LdapName dn);
+
+       Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly);
+
+       HierarchyUnit doGetHierarchyUnit(LdapName dn);
+
+       LdapEntry newUser(LdapName name);
+
+       LdapEntry newGroup(LdapName name);
+
+       void init();
+
+       void destroy();
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapEntry.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapEntry.java
new file mode 100644 (file)
index 0000000..fa95c96
--- /dev/null
@@ -0,0 +1,65 @@
+package org.argeo.cms.directory.ldap;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.TreeSet;
+
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+
+/** An LDAP entry. */
+public interface LdapEntry {
+       LdapName getDn();
+
+       Attributes getAttributes();
+
+       void publishAttributes(Attributes modifiedAttributes);
+
+       List<LdapName> getReferences(String attributeId);
+
+       Dictionary<String, Object> getProperties();
+
+       boolean hasCredential(String key, Object value);
+
+       /*
+        * UTILITIES
+        */
+       /**
+        * Convert a collection of object classes to the format expected by an LDAP
+        * backend.
+        */
+       public static void addObjectClasses(Dictionary<String, Object> properties, Collection<String> objectClasses) {
+               String value = properties.get(LdapAttr.objectClasses.name()).toString();
+               Set<String> currentObjectClasses = new TreeSet<>(Arrays.asList(value.toString().split("\n")));
+               currentObjectClasses.addAll(objectClasses);
+               StringJoiner values = new StringJoiner("\n");
+               currentObjectClasses.forEach((s) -> values.add(s));
+               properties.put(LdapAttr.objectClasses.name(), values.toString());
+       }
+
+       public static Object getLocalized(Dictionary<String, Object> properties, String key, Locale locale) {
+               if (locale == null)
+                       return null;
+               Object value = null;
+               value = properties.get(key + ";lang-" + locale.getLanguage() + "-" + locale.getCountry());
+               if (value == null)
+                       value = properties.get(key + ";lang-" + locale.getLanguage());
+               return value;
+       }
+
+       public static String toLocalizedKey(String key, Locale locale) {
+               String country = locale.getCountry();
+               if ("".equals(country)) {
+                       return key + ";lang-" + locale.getLanguage();
+               } else {
+                       return key + ";lang-" + locale.getLanguage() + "-" + locale.getCountry();
+               }
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapEntryWorkingCopy.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapEntryWorkingCopy.java
new file mode 100644 (file)
index 0000000..58e565a
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.cms.directory.ldap;
+
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.cms.transaction.AbstractWorkingCopy;
+
+/** Working copy for a user directory being edited. */
+public class LdapEntryWorkingCopy extends AbstractWorkingCopy<LdapEntry, Attributes, LdapName> {
+       @Override
+       protected LdapName getId(LdapEntry entry) {
+               return (LdapName) entry.getDn().clone();
+       }
+
+       @Override
+       protected Attributes cloneAttributes(LdapEntry entry) {
+               return (Attributes) entry.getAttributes().clone();
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapHierarchyUnit.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapHierarchyUnit.java
new file mode 100644 (file)
index 0000000..b60ee0c
--- /dev/null
@@ -0,0 +1,85 @@
+package org.argeo.cms.directory.ldap;
+
+import java.util.Locale;
+
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.argeo.api.cms.directory.HierarchyUnit;
+
+/** LDIF/LDAP based implementation of {@link HierarchyUnit}. */
+public class LdapHierarchyUnit extends DefaultLdapEntry implements HierarchyUnit {
+//     private final boolean functional;
+
+       private final Type type;
+
+       public LdapHierarchyUnit(AbstractLdapDirectory directory, LdapName dn) {
+               super(directory, dn);
+
+               Rdn rdn = LdapNameUtils.getLastRdn(dn);
+               if (directory.getUserBaseRdn().equals(rdn))
+                       type = Type.PEOPLE;
+               else if (directory.getGroupBaseRdn().equals(rdn))
+                       type = Type.GROUPS;
+               else if (directory.getSystemRoleBaseRdn().equals(rdn))
+                       type = Type.ROLES;
+               else
+                       type = Type.FUNCTIONAL;
+//             functional = !(directory.getUserBaseRdn().equals(rdn) || directory.getGroupBaseRdn().equals(rdn)
+//                             || directory.getSystemRoleBaseRdn().equals(rdn));
+       }
+
+       @Override
+       public HierarchyUnit getParent() {
+               return getDirectoryDao().doGetHierarchyUnit(LdapNameUtils.getParent(getDn()));
+       }
+
+       @Override
+       public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
+               return getDirectoryDao().doGetDirectHierarchyUnits(getDn(), functionalOnly);
+       }
+
+       @Override
+       public HierarchyUnit getDirectChild(Type type) {
+               return switch (type) {
+               case ROLES ->
+                       getDirectoryDao().doGetHierarchyUnit((LdapName) getDn().add(getDirectory().getSystemRoleBaseRdn()));
+               case PEOPLE -> getDirectoryDao().doGetHierarchyUnit((LdapName) getDn().add(getDirectory().getUserBaseRdn()));
+               case GROUPS -> getDirectoryDao().doGetHierarchyUnit((LdapName) getDn().add(getDirectory().getGroupBaseRdn()));
+               case FUNCTIONAL -> throw new IllegalArgumentException("Type must be a technical type");
+               };
+       }
+
+       @Override
+       public boolean isType(Type type) {
+               return this.type.equals(type);
+       }
+
+       @Override
+       public String getHierarchyUnitName() {
+               String name = LdapNameUtils.getLastRdnValue(getDn());
+               // TODO check ou, o, etc.
+               return name;
+       }
+
+       @Override
+       public String getHierarchyUnitLabel(Locale locale) {
+               String key = LdapNameUtils.getLastRdn(getDn()).getType();
+               Object value = LdapEntry.getLocalized(getProperties(), key, locale);
+               if (value == null)
+                       value = getHierarchyUnitName();
+               assert value != null;
+               return value.toString();
+       }
+
+       @Override
+       public String getBase() {
+               return getDn().toString();
+       }
+
+       @Override
+       public String toString() {
+               return "Hierarchy Unit " + getDn().toString();
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapNameUtils.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapNameUtils.java
new file mode 100644 (file)
index 0000000..74f23da
--- /dev/null
@@ -0,0 +1,69 @@
+package org.argeo.cms.directory.ldap;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+/** Utilities to simplify using {@link LdapName}. */
+public class LdapNameUtils {
+
+       public static LdapName relativeName(LdapName prefix, LdapName dn) {
+               try {
+                       if (!dn.startsWith(prefix))
+                               throw new IllegalArgumentException("Prefix " + prefix + " not consistent with " + dn);
+                       LdapName res = (LdapName) dn.clone();
+                       for (int i = 0; i < prefix.size(); i++) {
+                               res.remove(0);
+                       }
+                       return res;
+               } catch (InvalidNameException e) {
+                       throw new IllegalStateException("Cannot find realtive name", e);
+               }
+       }
+
+       public static LdapName getParent(LdapName dn) {
+               try {
+                       LdapName parent = (LdapName) dn.clone();
+                       parent.remove(parent.size() - 1);
+                       return parent;
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Cannot get parent of " + dn, e);
+               }
+       }
+
+       public static Rdn getParentRdn(LdapName dn) {
+               if (dn.size() < 2)
+                       throw new IllegalArgumentException(dn + " has no parent");
+               Rdn parentRdn = dn.getRdn(dn.size() - 2);
+               return parentRdn;
+       }
+
+       public static LdapName toLdapName(String distinguishedName) {
+               try {
+                       return new LdapName(distinguishedName);
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Cannot parse " + distinguishedName + " as LDAP name", e);
+               }
+       }
+
+       public static Rdn getLastRdn(LdapName dn) {
+               return dn.getRdn(dn.size() - 1);
+       }
+
+       public static String getLastRdnAsString(LdapName dn) {
+               return getLastRdn(dn).toString();
+       }
+
+       public static String getLastRdnValue(String dn) {
+               return getLastRdnValue(toLdapName(dn));
+       }
+
+       public static String getLastRdnValue(LdapName dn) {
+               return getLastRdn(dn).getValue().toString();
+       }
+
+       /** singleton */
+       private LdapNameUtils() {
+
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifDao.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifDao.java
new file mode 100644 (file)
index 0000000..52148df
--- /dev/null
@@ -0,0 +1,306 @@
+package org.argeo.cms.directory.ldap;
+
+import static org.argeo.api.acr.ldap.LdapAttr.objectClass;
+import static org.argeo.api.acr.ldap.LdapObj.inetOrgPerson;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.acr.ldap.LdapObj;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Role;
+
+/** A user admin based on a LDIF files. */
+public class LdifDao extends AbstractLdapDirectoryDao {
+       private NavigableMap<LdapName, LdapEntry> entries = new TreeMap<>();
+       private NavigableMap<LdapName, LdapHierarchyUnit> hierarchy = new TreeMap<>();
+
+       private NavigableMap<LdapName, Attributes> values = new TreeMap<>();
+
+       public LdifDao(AbstractLdapDirectory directory) {
+               super(directory);
+       }
+
+       public void init() {
+               String uri = getDirectory().getUri();
+               if (uri == null)
+                       return;
+               try {
+                       URI u = new URI(uri);
+                       if (u.getScheme().equals("file")) {
+                               File file = new File(u);
+                               if (!file.exists())
+                                       return;
+                       }
+                       load(u.toURL().openStream());
+               } catch (IOException | URISyntaxException e) {
+                       throw new IllegalStateException("Cannot open URL " + getDirectory().getUri(), e);
+               }
+       }
+
+       public void save() {
+               if (getDirectory().getUri() == null)
+                       return; // ignore
+               if (getDirectory().isReadOnly())
+                       throw new IllegalStateException(
+                                       "Cannot save LDIF user admin: " + getDirectory().getUri() + " is read-only");
+               try (FileOutputStream out = new FileOutputStream(new File(new URI(getDirectory().getUri())))) {
+                       save(out);
+               } catch (IOException | URISyntaxException e) {
+                       throw new IllegalStateException("Cannot save user admin to " + getDirectory().getUri(), e);
+               }
+       }
+
+       public void save(OutputStream out) throws IOException {
+               try {
+                       LdifWriter ldifWriter = new LdifWriter(out);
+                       for (LdapName name : hierarchy.keySet())
+                               ldifWriter.writeEntry(name, hierarchy.get(name).getAttributes());
+                       for (LdapName name : entries.keySet())
+                               ldifWriter.writeEntry(name, entries.get(name).getAttributes());
+               } finally {
+                       out.close();
+               }
+       }
+
+       public void load(InputStream in) {
+               try {
+                       entries.clear();
+                       hierarchy.clear();
+
+                       LdifParser ldifParser = new LdifParser();
+                       SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
+                       for (LdapName key : allEntries.keySet()) {
+                               Attributes attributes = allEntries.get(key);
+                               // check for inconsistency
+                               Set<String> lowerCase = new HashSet<String>();
+                               NamingEnumeration<String> ids = attributes.getIDs();
+                               while (ids.hasMoreElements()) {
+                                       String id = ids.nextElement().toLowerCase();
+                                       if (lowerCase.contains(id))
+                                               throw new IllegalStateException(key + " has duplicate id " + id);
+                                       lowerCase.add(id);
+                               }
+
+                               values.put(key, attributes);
+
+                               // analyse object classes
+                               NamingEnumeration<?> objectClasses = attributes.get(objectClass.name()).getAll();
+                               // System.out.println(key);
+                               objectClasses: while (objectClasses.hasMore()) {
+                                       String objectClass = objectClasses.next().toString();
+                                       // System.out.println(" " + objectClass);
+                                       if (objectClass.toLowerCase().equals(inetOrgPerson.name().toLowerCase())) {
+                                               entries.put(key, newUser(key));
+                                               break objectClasses;
+                                       } else if (objectClass.toLowerCase().equals(getDirectory().getGroupObjectClass().toLowerCase())) {
+                                               entries.put(key, newGroup(key));
+                                               break objectClasses;
+                                       } else if (objectClass.equalsIgnoreCase(LdapObj.organizationalUnit.name())) {
+                                               // TODO skip if it does not contain groups or users
+                                               hierarchy.put(key, new LdapHierarchyUnit(getDirectory(), key));
+                                               break objectClasses;
+                                       }
+                               }
+                       }
+
+               } catch (NamingException | IOException e) {
+                       throw new IllegalStateException("Cannot load user admin service from LDIF", e);
+               }
+       }
+
+       public void destroy() {
+//             if (users == null || groups == null)
+               if (entries == null)
+                       throw new IllegalStateException("User directory " + getDirectory().getBaseDn() + " is already destroyed");
+//             users = null;
+//             groups = null;
+               entries = null;
+       }
+
+       /*
+        * USER ADMIN
+        */
+
+       @Override
+       public LdapEntry doGetEntry(LdapName key) throws NameNotFoundException {
+               if (entries.containsKey(key))
+                       return entries.get(key);
+               throw new NameNotFoundException(key + " not persisted");
+       }
+
+       @Override
+       public Attributes doGetAttributes(LdapName name) {
+               if (!values.containsKey(name))
+                       throw new IllegalStateException(name + " doe not exist in " + getDirectory().getBaseDn());
+               return values.get(name);
+       }
+
+       @Override
+       public boolean checkConnection() {
+               return true;
+       }
+
+       @Override
+       public boolean entryExists(LdapName dn) {
+               return entries.containsKey(dn);// || groups.containsKey(dn);
+       }
+
+       @Override
+       public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
+               Objects.requireNonNull(searchBase);
+               ArrayList<LdapEntry> res = new ArrayList<>();
+               if (f == null && deep && getDirectory().getBaseDn().equals(searchBase)) {
+                       res.addAll(entries.values());
+               } else {
+                       filterRoles(entries, searchBase, f, deep, res);
+               }
+               return res;
+       }
+
+       private void filterRoles(SortedMap<LdapName, ? extends LdapEntry> map, LdapName searchBase, String f, boolean deep,
+                       List<LdapEntry> res) {
+               // FIXME get rid of OSGi references
+               try {
+                       // TODO reduce map with search base ?
+                       Filter filter = f != null ? FrameworkUtil.createFilter(f) : null;
+                       roles: for (LdapEntry user : map.values()) {
+                               LdapName dn = user.getDn();
+                               if (dn.startsWith(searchBase)) {
+                                       if (!deep && dn.size() != (searchBase.size() + 1))
+                                               continue roles;
+                                       if (filter == null)
+                                               res.add(user);
+                                       else {
+                                               if (user instanceof Role) {
+                                                       if (filter.match(((Role) user).getProperties()))
+                                                               res.add(user);
+                                               }
+                                       }
+                               }
+                       }
+               } catch (InvalidSyntaxException e) {
+                       throw new IllegalArgumentException("Cannot create filter " + f, e);
+               }
+
+       }
+
+       @Override
+       public List<LdapName> getDirectGroups(LdapName dn) {
+               List<LdapName> directGroups = new ArrayList<LdapName>();
+               entries: for (LdapName name : entries.keySet()) {
+                       LdapEntry group;
+                       try {
+                               LdapEntry entry = doGetEntry(name);
+                               if (AbstractLdapDirectory.hasObjectClass(entry.getAttributes(), getDirectory().getGroupObjectClass())) {
+                                       group = entry;
+                               } else {
+                                       continue entries;
+                               }
+                       } catch (NameNotFoundException e) {
+                               throw new IllegalArgumentException("Group " + dn + " not found", e);
+                       }
+                       if (group.getReferences(getDirectory().getMemberAttributeId()).contains(dn)) {
+                               directGroups.add(group.getDn());
+                       }
+               }
+               return directGroups;
+       }
+
+       @Override
+       public void prepare(LdapEntryWorkingCopy wc) {
+               // delete
+               for (LdapName dn : wc.getDeletedData().keySet()) {
+                       if (entries.containsKey(dn))
+                               entries.remove(dn);
+                       else
+                               throw new IllegalStateException("User to delete not found " + dn);
+               }
+               // add
+               for (LdapName dn : wc.getNewData().keySet()) {
+                       LdapEntry user = (LdapEntry) wc.getNewData().get(dn);
+                       if (entries.containsKey(dn))
+                               throw new IllegalStateException("User to create found " + dn);
+                       entries.put(dn, user);
+               }
+               // modify
+               for (LdapName dn : wc.getModifiedData().keySet()) {
+                       Attributes modifiedAttrs = wc.getModifiedData().get(dn);
+                       LdapEntry user;
+                       try {
+                               user = doGetEntry(dn);
+                       } catch (NameNotFoundException e) {
+                               throw new IllegalStateException("User to modify no found " + dn, e);
+                       }
+                       if (user == null)
+                               throw new IllegalStateException("User to modify no found " + dn);
+                       user.publishAttributes(modifiedAttrs);
+               }
+       }
+
+       @Override
+       public void commit(LdapEntryWorkingCopy wc) {
+               save();
+       }
+
+       @Override
+       public void rollback(LdapEntryWorkingCopy wc) {
+               init();
+       }
+
+       /*
+        * HIERARCHY
+        */
+       @Override
+       public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
+               if (getDirectory().getBaseDn().equals(dn))
+                       return getDirectory();
+               return hierarchy.get(dn);
+       }
+
+       @Override
+       public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
+               List<HierarchyUnit> res = new ArrayList<>();
+               for (LdapName n : hierarchy.keySet()) {
+                       if (n.size() == searchBase.size() + 1) {
+                               if (n.startsWith(searchBase)) {
+                                       HierarchyUnit hu = hierarchy.get(n);
+                                       if (functionalOnly) {
+                                               if (hu.isFunctional())
+                                                       res.add(hu);
+                                       } else {
+                                               res.add(hu);
+                                       }
+                               }
+                       }
+               }
+               return res;
+       }
+
+       public void scope(LdifDao scoped) {
+               scoped.entries = Collections.unmodifiableNavigableMap(entries);
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifParser.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifParser.java
new file mode 100644 (file)
index 0000000..d0e6b76
--- /dev/null
@@ -0,0 +1,161 @@
+package org.argeo.cms.directory.ldap;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.naming.InvalidNameException;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+
+/** Basic LDIF parser. */
+public class LdifParser {
+       private final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
+
+       protected Attributes addAttributes(SortedMap<LdapName, Attributes> res, int lineNumber, LdapName currentDn,
+                       Attributes currentAttributes) {
+               try {
+                       Rdn nameRdn = currentDn.getRdn(currentDn.size() - 1);
+                       Attribute nameAttr = currentAttributes.get(nameRdn.getType());
+                       if (nameAttr == null)
+                               currentAttributes.put(nameRdn.getType(), nameRdn.getValue());
+                       else if (!nameAttr.get().equals(nameRdn.getValue()))
+                               throw new IllegalStateException(
+                                               "Attribute " + nameAttr.getID() + "=" + nameAttr.get() + " not consistent with DN " + currentDn
+                                                               + " (shortly before line " + lineNumber + " in LDIF file)");
+                       Attributes previous = res.put(currentDn, currentAttributes);
+                       return previous;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot add " + currentDn, e);
+               }
+       }
+
+       /** With UTF-8 charset */
+       public SortedMap<LdapName, Attributes> read(InputStream in) throws IOException {
+               try (Reader reader = new InputStreamReader(in, DEFAULT_CHARSET)) {
+                       return read(reader);
+               } finally {
+                       try {
+                               in.close();
+                       } catch (IOException e) {
+                               // silent
+                       }
+               }
+       }
+
+       /** Will close the reader. */
+       public SortedMap<LdapName, Attributes> read(Reader reader) throws IOException {
+               SortedMap<LdapName, Attributes> res = new TreeMap<LdapName, Attributes>();
+               try {
+                       List<String> lines = new ArrayList<>();
+                       try (BufferedReader br = new BufferedReader(reader)) {
+                               String line;
+                               while ((line = br.readLine()) != null) {
+                                       lines.add(line);
+                               }
+                       }
+                       if (lines.size() == 0)
+                               return res;
+                       // add an empty new line since the last line is not checked
+                       if (!lines.get(lines.size() - 1).equals(""))
+                               lines.add("");
+
+                       LdapName currentDn = null;
+                       Attributes currentAttributes = null;
+                       StringBuilder currentEntry = new StringBuilder();
+
+                       readLines: for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
+                               String line = lines.get(lineNumber);
+                               boolean isLastLine = false;
+                               if (lineNumber == lines.size() - 1)
+                                       isLastLine = true;
+                               if (line.startsWith(" ")) {
+                                       currentEntry.append(line.substring(1));
+                                       if (!isLastLine)
+                                               continue readLines;
+                               }
+
+                               if (currentEntry.length() != 0 || isLastLine) {
+                                       // read previous attribute
+                                       StringBuilder attrId = new StringBuilder(8);
+                                       boolean isBase64 = false;
+                                       readAttrId: for (int i = 0; i < currentEntry.length(); i++) {
+                                               char c = currentEntry.charAt(i);
+                                               if (c == ':') {
+                                                       if (i + 1 < currentEntry.length() && currentEntry.charAt(i + 1) == ':')
+                                                               isBase64 = true;
+                                                       currentEntry.delete(0, i + (isBase64 ? 2 : 1));
+                                                       break readAttrId;
+                                               } else {
+                                                       attrId.append(c);
+                                               }
+                                       }
+
+                                       String attributeId = attrId.toString();
+                                       // TODO should we really trim the end of the string as well?
+                                       String cleanValueStr = currentEntry.toString().trim();
+                                       Object attributeValue = isBase64 ? Base64.getDecoder().decode(cleanValueStr) : cleanValueStr;
+
+                                       // manage DN attributes
+                                       if (attributeId.equals(LdapAttr.DN) || isLastLine) {
+                                               if (currentDn != null) {
+                                                       //
+                                                       // ADD
+                                                       //
+                                                       Attributes previous = addAttributes(res, lineNumber, currentDn, currentAttributes);
+                                                       if (previous != null) {
+//                                                             log.warn("There was already an entry with DN " + currentDn
+//                                                                             + ", which has been discarded by a subsequent one.");
+                                                       }
+                                               }
+
+                                               if (attributeId.equals(LdapAttr.DN))
+                                                       try {
+                                                               currentDn = new LdapName(attributeValue.toString());
+                                                               currentAttributes = new BasicAttributes(true);
+                                                       } catch (InvalidNameException e) {
+//                                                             log.error(attributeValue + " not a valid DN, skipping the entry.");
+                                                               currentDn = null;
+                                                               currentAttributes = null;
+                                                       }
+                                       }
+
+                                       // store attribute
+                                       if (currentAttributes != null) {
+                                               Attribute attribute = currentAttributes.get(attributeId);
+                                               if (attribute == null) {
+                                                       attribute = new BasicAttribute(attributeId);
+                                                       currentAttributes.put(attribute);
+                                               }
+                                               attribute.add(attributeValue);
+                                       }
+                                       currentEntry = new StringBuilder();
+                               }
+                               currentEntry.append(line);
+                       }
+               } finally {
+                       try {
+                               reader.close();
+                       } catch (IOException e) {
+                               // silent
+                       }
+               }
+               return res;
+       }
+}
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifWriter.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdifWriter.java
new file mode 100644 (file)
index 0000000..69a8672
--- /dev/null
@@ -0,0 +1,104 @@
+package org.argeo.cms.directory.ldap;
+
+import static org.argeo.api.acr.ldap.LdapAttr.DN;
+import static org.argeo.api.acr.ldap.LdapAttr.member;
+import static org.argeo.api.acr.ldap.LdapAttr.objectClass;
+import static org.argeo.api.acr.ldap.LdapAttr.uniqueMember;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+/** Basic LDIF writer */
+public class LdifWriter {
+       private final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
+       private final Writer writer;
+
+       /** Writer must be closed by caller */
+       public LdifWriter(Writer writer) {
+               this.writer = writer;
+       }
+
+       /** Stream must be closed by caller */
+       public LdifWriter(OutputStream out) {
+               this(new OutputStreamWriter(out, DEFAULT_CHARSET));
+       }
+
+       public void writeEntry(LdapName name, Attributes attributes) throws IOException {
+               try {
+                       // check consistency
+                       Rdn nameRdn = name.getRdn(name.size() - 1);
+                       Attribute nameAttr = attributes.get(nameRdn.getType());
+                       if (!nameAttr.get().equals(nameRdn.getValue()))
+                               throw new IllegalArgumentException(
+                                               "Attribute " + nameAttr.getID() + "=" + nameAttr.get() + " not consistent with DN " + name);
+
+                       writer.append(DN + ": ").append(name.toString()).append('\n');
+                       Attribute objectClassAttr = attributes.get(objectClass.name());
+                       if (objectClassAttr != null)
+                               writeAttribute(objectClassAttr);
+                       attributes: for (NamingEnumeration<? extends Attribute> attrs = attributes.getAll(); attrs.hasMore();) {
+                               Attribute attribute = attrs.next();
+                               if (attribute.getID().equals(DN) || attribute.getID().equals(objectClass.name()))
+                                       continue attributes;// skip DN attribute
+                               if (attribute.getID().equals(member.name()) || attribute.getID().equals(uniqueMember.name()))
+                                       continue attributes;// skip member and uniqueMember attributes, so that they are always written last
+                               writeAttribute(attribute);
+                       }
+                       // write member and uniqueMember attributes last
+                       for (NamingEnumeration<? extends Attribute> attrs = attributes.getAll(); attrs.hasMore();) {
+                               Attribute attribute = attrs.next();
+                               if (attribute.getID().equals(member.name()) || attribute.getID().equals(uniqueMember.name()))
+                                       writeMemberAttribute(attribute);
+                       }
+                       writer.append('\n');
+                       writer.flush();
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot write LDIF", e);
+               }
+       }
+
+       public void write(Map<LdapName, Attributes> entries) throws IOException {
+               for (LdapName dn : entries.keySet())
+                       writeEntry(dn, entries.get(dn));
+       }
+
+       protected void writeAttribute(Attribute attribute) throws NamingException, IOException {
+               for (NamingEnumeration<?> attrValues = attribute.getAll(); attrValues.hasMore();) {
+                       Object value = attrValues.next();
+                       if (value instanceof byte[]) {
+                               String encoded = Base64.getEncoder().encodeToString((byte[]) value);
+                               writer.append(attribute.getID()).append(":: ").append(encoded).append('\n');
+                       } else {
+                               writer.append(attribute.getID()).append(": ").append(value.toString()).append('\n');
+                       }
+               }
+       }
+
+       protected void writeMemberAttribute(Attribute attribute) throws NamingException, IOException {
+               // Note: duplicate entries will be swallowed
+               SortedSet<String> values = new TreeSet<>();
+               for (NamingEnumeration<?> attrValues = attribute.getAll(); attrValues.hasMore();) {
+                       String value = attrValues.next().toString();
+                       values.add(value);
+               }
+
+               for (String value : values) {
+                       writer.append(attribute.getID()).append(": ").append(value).append('\n');
+               }
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/SharedSecret.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/SharedSecret.java
new file mode 100644 (file)
index 0000000..2c52ee1
--- /dev/null
@@ -0,0 +1,48 @@
+package org.argeo.cms.directory.ldap;
+
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import org.argeo.api.acr.ldap.NamingUtils;
+
+public class SharedSecret extends AuthPassword {
+       public final static String X_SHARED_SECRET = "X-SharedSecret";
+       private final Instant expiry;
+
+       public SharedSecret(String authInfo, String authValue) {
+               super(authInfo, authValue);
+               expiry = null;
+       }
+
+       public SharedSecret(AuthPassword authPassword) {
+               super(authPassword);
+               String authInfo = getAuthInfo();
+               if (authInfo.length() == 16) {
+                       expiry = NamingUtils.ldapDateToInstant(authInfo);
+               } else {
+                       expiry = null;
+               }
+       }
+
+       public SharedSecret(ZonedDateTime expiryTimestamp, String value) {
+               super(NamingUtils.instantToLdapDate(expiryTimestamp), value);
+               expiry = expiryTimestamp.withZoneSameInstant(ZoneOffset.UTC).toInstant();
+       }
+
+       public SharedSecret(int hours, String value) {
+               this(ZonedDateTime.now().plusHours(hours), value);
+       }
+
+       @Override
+       protected String getExpectedAuthScheme() {
+               return X_SHARED_SECRET;
+       }
+
+       public boolean isExpired() {
+               if (expiry == null)
+                       return false;
+               return expiry.isBefore(Instant.now());
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/dns/DnsBrowser.java b/org.argeo.cms/src/org/argeo/cms/dns/DnsBrowser.java
new file mode 100644 (file)
index 0000000..c6b6530
--- /dev/null
@@ -0,0 +1,216 @@
+package org.argeo.cms.dns;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.SortedSet;
+import java.util.StringJoiner;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+
+public class DnsBrowser implements Closeable {
+       private final DirContext initialCtx;
+
+       public DnsBrowser() {
+               this(new ArrayList<>());
+       }
+
+       public DnsBrowser(List<String> dnsServerUrls) {
+               try {
+                       Objects.requireNonNull(dnsServerUrls);
+                       Hashtable<String, Object> env = new Hashtable<>();
+                       env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
+                       if (!dnsServerUrls.isEmpty()) {
+                               boolean specified = false;
+                               StringJoiner providerUrl = new StringJoiner(" ");
+                               for (String dnsUrl : dnsServerUrls) {
+                                       if (dnsUrl != null) {
+                                               providerUrl.add(dnsUrl);
+                                               specified = true;
+                                       }
+                               }
+                               if (specified)
+                                       env.put(Context.PROVIDER_URL, providerUrl.toString());
+                       }
+                       initialCtx = new InitialDirContext(env);
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot initialise DNS borowser.", e);
+               }
+       }
+
+       public Map<String, List<String>> getAllRecords(String name) {
+               try {
+                       Map<String, List<String>> res = new TreeMap<>();
+                       Attributes attrs = initialCtx.getAttributes(name);
+                       NamingEnumeration<String> ids = attrs.getIDs();
+                       while (ids.hasMore()) {
+                               String recordType = ids.next();
+                               List<String> lst = new ArrayList<String>();
+                               res.put(recordType, lst);
+                               Attribute attr = attrs.get(recordType);
+                               addValues(attr, lst);
+                       }
+                       return Collections.unmodifiableMap(res);
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get allrecords of " + name, e);
+               }
+       }
+
+       /**
+        * Return a single record (typically A, AAAA, etc. or null if not available.
+        * Will fail if multiple records.
+        */
+       public String getRecord(String name, String recordType) {
+               try {
+                       Attributes attrs = initialCtx.getAttributes(name, new String[] { recordType });
+                       if (attrs.size() == 0)
+                               return null;
+                       Attribute attr = attrs.get(recordType);
+                       if (attr.size() > 1)
+                               throw new IllegalArgumentException("Multiple record type " + recordType);
+                       assert attr.size() != 0;
+                       Object value = attr.get();
+                       assert value != null;
+                       return value.toString();
+               } catch (NameNotFoundException e) {
+                       return null;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get DNS entry " + recordType + " of " + name, e);
+               }
+       }
+
+       /**
+        * Return records of a given type.
+        */
+       public List<String> getRecords(String name, String recordType) {
+               try {
+                       List<String> res = new ArrayList<String>();
+                       Attributes attrs = initialCtx.getAttributes(name, new String[] { recordType });
+                       Attribute attr = attrs.get(recordType);
+                       addValues(attr, res);
+                       return res;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot get records " + recordType + " of " + name, e);
+               }
+       }
+
+       /** Ordered, with preferred first. */
+       public List<String> getSrvRecordsAsHosts(String name, boolean withPort) {
+               List<String> raw = getRecords(name, "SRV");
+               if (raw.size() == 0)
+                       return null;
+               SortedSet<SrvRecord> res = new TreeSet<>();
+               for (int i = 0; i < raw.size(); i++) {
+                       String record = raw.get(i);
+                       String[] arr = record.split(" ");
+                       Integer priority = Integer.parseInt(arr[0]);
+                       Integer weight = Integer.parseInt(arr[1]);
+                       Integer port = Integer.parseInt(arr[2]);
+                       String hostname = arr[3];
+                       SrvRecord order = new SrvRecord(priority, weight, port, hostname);
+                       res.add(order);
+               }
+               List<String> lst = new ArrayList<>();
+               for (SrvRecord order : res) {
+                       lst.add(order.toHost(withPort));
+               }
+               return Collections.unmodifiableList(lst);
+       }
+
+       private void addValues(Attribute attr, List<String> lst) throws NamingException {
+               NamingEnumeration<?> values = attr.getAll();
+               while (values.hasMore()) {
+                       Object value = values.next();
+                       if (value != null) {
+                               if (value instanceof byte[]) {
+                                       String str = Base64.getEncoder().encodeToString((byte[]) value);
+                                       lst.add(str);
+                               } else
+                                       lst.add(value.toString());
+                       }
+               }
+
+       }
+
+       public List<String> listEntries(String name) {
+               try {
+                       List<String> res = new ArrayList<String>();
+                       NamingEnumeration<Binding> ne = initialCtx.listBindings(name);
+                       while (ne.hasMore()) {
+                               Binding b = ne.next();
+                               res.add(b.getName());
+                       }
+                       return Collections.unmodifiableList(res);
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot list entries of " + name, e);
+               }
+       }
+
+       @Override
+       public void close() throws IOException {
+               destroy();
+       }
+
+       public void destroy() {
+               try {
+                       initialCtx.close();
+               } catch (NamingException e) {
+                       // silent
+               }
+       }
+
+       public static void main(String[] args) {
+               if (args.length == 0) {
+                       printUsage(System.err);
+                       System.exit(1);
+               }
+               try (DnsBrowser dnsBrowser = new DnsBrowser()) {
+                       String hostname = args[0];
+                       String recordType = args.length > 1 ? args[1] : "A";
+                       if (recordType.equals("*")) {
+                               Map<String, List<String>> records = dnsBrowser.getAllRecords(hostname);
+                               for (String type : records.keySet()) {
+                                       for (String record : records.get(type)) {
+                                               String typeLabel;
+                                               if ("44".equals(type))
+                                                       typeLabel = "SSHFP";
+                                               else if ("46".equals(type))
+                                                       typeLabel = "RRSIG";
+                                               else if ("48".equals(type))
+                                                       typeLabel = "DNSKEY";
+                                               else
+                                                       typeLabel = type;
+                                               System.out.println(typeLabel + "\t" + record);
+                                       }
+                               }
+                       } else {
+                               System.out.println(dnsBrowser.getRecord(hostname, recordType));
+                       }
+
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static void printUsage(PrintStream out) {
+               out.println("java org.argeo.naming.DnsBrowser <hostname> [<record type> | *]");
+       }
+
+}
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/dns/SrvRecord.java b/org.argeo.cms/src/org/argeo/cms/dns/SrvRecord.java
new file mode 100644 (file)
index 0000000..bdbdc76
--- /dev/null
@@ -0,0 +1,52 @@
+package org.argeo.cms.dns;
+
+class SrvRecord implements Comparable<SrvRecord> {
+       private final Integer priority;
+       private final Integer weight;
+       private final Integer port;
+       private final String hostname;
+
+       public SrvRecord(Integer priority, Integer weight, Integer port, String hostname) {
+               this.priority = priority;
+               this.weight = weight;
+               this.port = port;
+               this.hostname = hostname;
+       }
+
+       @Override
+       public int compareTo(SrvRecord other) {
+               // https: // en.wikipedia.org/wiki/SRV_record
+               if (priority != other.priority)
+                       return priority - other.priority;
+               if (weight != other.weight)
+                       return other.weight - other.weight;
+               String host = toHost(false);
+               String otherHost = other.toHost(false);
+               if (host.length() == otherHost.length())
+                       return host.compareTo(otherHost);
+               else
+                       return host.length() - otherHost.length();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof SrvRecord) {
+                       SrvRecord other = (SrvRecord) obj;
+                       return priority == other.priority && weight == other.weight && port == other.port
+                                       && hostname.equals(other.hostname);
+               }
+               return false;
+       }
+
+       @Override
+       public String toString() {
+               return priority + " " + weight;
+       }
+
+       public String toHost(boolean withPort) {
+               String hostStr = hostname;
+               if (hostname.charAt(hostname.length() - 1) == '.')
+                       hostStr = hostname.substring(0, hostname.length() - 1);
+               return hostStr + (withPort ? ":" + port : "");
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/file/ChecksumFactory.java b/org.argeo.cms/src/org/argeo/cms/file/ChecksumFactory.java
new file mode 100644 (file)
index 0000000..6aea8be
--- /dev/null
@@ -0,0 +1,149 @@
+package org.argeo.cms.file;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.zip.Checksum;
+
+/** Allows to fine tune how files are read. */
+public class ChecksumFactory {
+       private int regionSize = 10 * 1024 * 1024;
+
+       public byte[] digest(Path path, final String algo) {
+               try {
+                       final MessageDigest md = MessageDigest.getInstance(algo);
+                       if (Files.isDirectory(path)) {
+                               long begin = System.currentTimeMillis();
+                               Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+
+                                       @Override
+                                       public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                                               if (!Files.isDirectory(file)) {
+                                                       byte[] digest = digest(file, algo);
+                                                       md.update(digest);
+                                               }
+                                               return FileVisitResult.CONTINUE;
+                                       }
+
+                               });
+                               byte[] digest = md.digest();
+                               long duration = System.currentTimeMillis() - begin;
+                               System.out.println(printBase64Binary(digest) + " " + path + " (" + duration / 1000 + "s)");
+                               return digest;
+                       } else {
+                               long begin = System.nanoTime();
+                               long length = -1;
+                               try (FileChannel channel = (FileChannel) Files.newByteChannel(path);) {
+                                       length = channel.size();
+                                       long cursor = 0;
+                                       while (cursor < length) {
+                                               long effectiveSize = Math.min(regionSize, length - cursor);
+                                               MappedByteBuffer mb = channel.map(FileChannel.MapMode.READ_ONLY, cursor, effectiveSize);
+                                               // md.update(mb);
+                                               byte[] buffer = new byte[1024];
+                                               while (mb.hasRemaining()) {
+                                                       mb.get(buffer);
+                                                       md.update(buffer);
+                                               }
+
+                                               // sub digest
+                                               // mb.flip();
+                                               // MessageDigest subMd =
+                                               // MessageDigest.getInstance(algo);
+                                               // subMd.update(mb);
+                                               // byte[] subDigest = subMd.digest();
+                                               // System.out.println(" -> " + cursor);
+                                               // System.out.println(IOUtils.encodeHexString(subDigest));
+                                               // System.out.println(new BigInteger(1,
+                                               // subDigest).toString(16));
+                                               // System.out.println(new BigInteger(1, subDigest)
+                                               // .toString(Character.MAX_RADIX));
+                                               // System.out.println(printBase64Binary(subDigest));
+
+                                               cursor = cursor + regionSize;
+                                       }
+                                       byte[] digest = md.digest();
+                                       long duration = System.nanoTime() - begin;
+                                       System.out.println(printBase64Binary(digest) + " " + path.getFileName() + " (" + duration / 1000000
+                                                       + "ms, " + (length / 1024) + "kB, " + (length / (duration / 1000000)) * 1000 / (1024 * 1024)
+                                                       + " MB/s)");
+                                       return digest;
+                               }
+                       }
+               } catch (NoSuchAlgorithmException | IOException e) {
+                       throw new IllegalStateException("Cannot digest " + path, e);
+               }
+       }
+
+       /** Whether the file should be mapped. */
+       protected boolean mapFile(FileChannel fileChannel) throws IOException {
+               long size = fileChannel.size();
+               if (size > (regionSize / 10))
+                       return true;
+               return false;
+       }
+
+       public long checksum(Path path, Checksum crc) {
+               final int bufferSize = 2 * 1024 * 1024;
+               long begin = System.currentTimeMillis();
+               try (FileChannel channel = (FileChannel) Files.newByteChannel(path);) {
+                       byte[] bytes = new byte[bufferSize];
+                       long length = channel.size();
+                       long cursor = 0;
+                       while (cursor < length) {
+                               long effectiveSize = Math.min(regionSize, length - cursor);
+                               MappedByteBuffer mb = channel.map(FileChannel.MapMode.READ_ONLY, cursor, effectiveSize);
+                               int nGet;
+                               while (mb.hasRemaining()) {
+                                       nGet = Math.min(mb.remaining(), bufferSize);
+                                       mb.get(bytes, 0, nGet);
+                                       crc.update(bytes, 0, nGet);
+                               }
+                               cursor = cursor + regionSize;
+                       }
+                       return crc.getValue();
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot checksum " + path, e);
+               } finally {
+                       long duration = System.currentTimeMillis() - begin;
+                       System.out.println(duration / 1000 + "s");
+               }
+       }
+
+       public static void main(String... args) {
+               ChecksumFactory cf = new ChecksumFactory();
+               // Path path =
+               // Paths.get("/home/mbaudier/apache-maven-3.2.3-bin.tar.gz");
+               Path path;
+               if (args.length > 0) {
+                       path = Paths.get(args[0]);
+               } else {
+                       path = Paths.get("/home/mbaudier/Downloads/torrents/CentOS-7-x86_64-DVD-1503-01/"
+                                       + "CentOS-7-x86_64-DVD-1503-01.iso");
+               }
+               // long adler = cf.checksum(path, new Adler32());
+               // System.out.format("Adler=%d%n", adler);
+               // long crc = cf.checksum(path, new CRC32());
+               // System.out.format("CRC=%d%n", crc);
+               String algo = "SHA1";
+               byte[] digest = cf.digest(path, algo);
+               System.out.println(algo + " " + printBase64Binary(digest));
+               System.out.println(algo + " " + new BigInteger(1, digest).toString(16));
+               // String sha1 = printBase64Binary(cf.digest(path, "SHA1"));
+               // System.out.format("SHA1=%s%n", sha1);
+       }
+
+       private static String printBase64Binary(byte[] arr) {
+               return Base64.getEncoder().encodeToString(arr);
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/http/HttpHeader.java b/org.argeo.cms/src/org/argeo/cms/http/HttpHeader.java
new file mode 100644 (file)
index 0000000..ef7385d
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.cms.http;
+
+/** Selection of standard or common HTTP headers (including WebDav). */
+public enum HttpHeader {
+       AUTHORIZATION("Authorization"), //
+       WWW_AUTHENTICATE("WWW-Authenticate"), //
+       ALLOW("Allow"), //
+       VIA("Via"), //
+
+       // WebDav
+       DAV("DAV"), //
+       DEPTH("Depth"), //
+
+       // Non-standard
+       X_FORWARDED_HOST("X-Forwarded-Host"), //
+       ;
+
+       public final static String BASIC = "Basic";
+       public final static String REALM = "realm";
+       public final static String NEGOTIATE = "Negotiate";
+
+       private final String name;
+
+       private HttpHeader(String headerName) {
+               this.name = headerName;
+       }
+
+       public String getHeaderName() {
+               return name;
+       }
+
+       @Override
+       public String toString() {
+               return getHeaderName();
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/http/HttpMethod.java b/org.argeo.cms/src/org/argeo/cms/http/HttpMethod.java
new file mode 100644 (file)
index 0000000..7869045
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.cms.http;
+
+/** Generic HTTP methods. */
+public enum HttpMethod {
+       OPTIONS, //
+       HEAD, //
+       GET, //
+       POST, //
+       PUT, //
+       DELETE, //
+
+       // WebDav
+       PROPFIND, //
+       PROPPATCH, //
+       MKCOL, //
+       MOVE, //
+       COPY, //
+       ;
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/http/HttpStatus.java b/org.argeo.cms/src/org/argeo/cms/http/HttpStatus.java
new file mode 100644 (file)
index 0000000..3b9a47a
--- /dev/null
@@ -0,0 +1,66 @@
+package org.argeo.cms.http;
+
+/**
+ * Standard HTTP response status codes (including WebDav ones).
+ * 
+ * @see "https://developer.mozilla.org/en-US/docs/Web/HTTP/Status"
+ */
+public enum HttpStatus {
+       // Successful responses (200–299)
+       OK(200, "OK"), //
+       NO_CONTENT(204, "No Content"), //
+       MULTI_STATUS(207, "Multi-Status"), // WebDav
+       // Client error responses (400–499)
+       UNAUTHORIZED(401, "Unauthorized"), //
+       FORBIDDEN(403, "Forbidden"), //
+       NOT_FOUND(404, "Not Found"), //
+       // Server error responses (500-599)
+       INTERNAL_SERVER_ERROR(500, "Internal Server Error"), //
+       NOT_IMPLEMENTED(501, "Not Implemented"), //
+       ;
+
+       private final int code;
+       private final String reasonPhrase;
+
+       HttpStatus(int statusCode, String reasonPhrase) {
+               this.code = statusCode;
+               this.reasonPhrase = reasonPhrase;
+       }
+
+       public int getCode() {
+               return code;
+       }
+
+       public String getReasonPhrase() {
+               return reasonPhrase;
+       }
+
+       /**
+        * The status line, as defined by RFC2616.
+        * 
+        * @see "https://www.rfc-editor.org/rfc/rfc2616#section-6.1"
+        */
+       public String getStatusLine(String httpVersion) {
+               return httpVersion + " " + code + " " + reasonPhrase;
+       }
+
+       public static HttpStatus parseStatusLine(String statusLine) {
+               try {
+                       String[] arr = statusLine.split(" ");
+                       int code = Integer.parseInt(arr[1]);
+                       for (HttpStatus status : values()) {
+                               if (status.getCode() == code)
+                                       return status;
+                       }
+               } catch (Exception e) {
+                       throw new IllegalArgumentException("Invalid status line: " + statusLine, e);
+               }
+               throw new IllegalArgumentException("Unkown status code: " + statusLine);
+       }
+
+       @Override
+       public String toString() {
+               return code + " " + reasonPhrase;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/http/server/HttpServerUtils.java b/org.argeo.cms/src/org/argeo/cms/http/server/HttpServerUtils.java
new file mode 100644 (file)
index 0000000..ab033f0
--- /dev/null
@@ -0,0 +1,46 @@
+package org.argeo.cms.http.server;
+
+import java.net.URI;
+import java.util.Objects;
+
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+
+/** HTTP utilities on the server-side. */
+public class HttpServerUtils {
+       private final static String SLASH = "/";
+
+       private static String extractPathWithingContext(HttpContext httpContext, String fullPath, boolean startWithSlash) {
+               Objects.requireNonNull(fullPath);
+               String contextPath = httpContext.getPath();
+               if (!fullPath.startsWith(contextPath))
+                       throw new IllegalArgumentException(fullPath + " does not belong to context" + contextPath);
+               String path = fullPath.substring(contextPath.length());
+               // TODO optimise?
+               if (!startWithSlash && path.startsWith(SLASH)) {
+                       path = path.substring(1);
+               } else if (startWithSlash && !path.startsWith(SLASH)) {
+                       path = SLASH + path;
+               }
+               return path;
+       }
+
+       /** Path within the context, NOT starting with a slash. */
+       public static String relativize(HttpExchange exchange) {
+               URI uri = exchange.getRequestURI();
+               HttpContext httpContext = exchange.getHttpContext();
+               return extractPathWithingContext(httpContext, uri.getPath(), false);
+       }
+
+       /** Path within the context, starting with a slash. */
+       public static String subPath(HttpExchange exchange) {
+               URI uri = exchange.getRequestURI();
+               HttpContext httpContext = exchange.getHttpContext();
+               return extractPathWithingContext(httpContext, uri.getPath(), true);
+       }
+
+       /** singleton */
+       private HttpServerUtils() {
+
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java
deleted file mode 100644 (file)
index b744563..0000000
+++ /dev/null
@@ -1,712 +0,0 @@
-package org.argeo.cms.internal.auth;
-
-import static org.argeo.util.naming.LdapAttrs.cn;
-import static org.argeo.util.naming.LdapAttrs.description;
-import static org.argeo.util.naming.LdapAttrs.owner;
-
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.UUID;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.security.auth.Subject;
-
-import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.CmsUserManager;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.SystemRole;
-import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.osgi.useradmin.AggregatingUserAdmin;
-import org.argeo.osgi.useradmin.TokenUtils;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.directory.ldap.LdapEntry;
-import org.argeo.util.directory.ldap.SharedSecret;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.NamingUtils;
-import org.argeo.util.transaction.WorkTransaction;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-/**
- * Canonical implementation of the people {@link CmsUserManager}. Wraps
- * interaction with users and groups.
- * 
- * In a *READ-ONLY* mode. We want to be able to:
- * <ul>
- * <li>Retrieve my user and corresponding information (main info,
- * groups...)</li>
- * <li>List all local groups (not the system roles)</li>
- * <li>If sufficient rights: retrieve a given user and its information</li>
- * </ul>
- */
-public class CmsUserManagerImpl implements CmsUserManager {
-       private final static CmsLog log = CmsLog.getLog(CmsUserManagerImpl.class);
-
-       private UserAdmin userAdmin;
-//     private Map<String, String> serviceProperties;
-       private WorkTransaction userTransaction;
-
-       private final String[] knownProps = { LdapAttrs.cn.name(), LdapAttrs.sn.name(), LdapAttrs.givenName.name(),
-                       LdapAttrs.uid.name() };
-
-//     private Map<UserDirectory, Hashtable<String, Object>> userDirectories = Collections
-//                     .synchronizedMap(new LinkedHashMap<>());
-
-       private Set<UserDirectory> userDirectories = new HashSet<>();
-
-       public void start() {
-               log.debug(() -> "CMS user manager available");
-       }
-
-       public void stop() {
-
-       }
-
-       @Override
-       public String getMyMail() {
-               return getUserMail(CurrentUser.getUsername());
-       }
-
-       @Override
-       public Role[] getRoles(String filter) throws InvalidSyntaxException {
-               return userAdmin.getRoles(filter);
-       }
-
-       // ALL USER: WARNING access to this will be later reduced
-
-       /** Retrieve a user given his dn, or <code>null</code> if it doesn't exist. */
-       public User getUser(String dn) {
-               return (User) getUserAdmin().getRole(dn);
-       }
-
-       /** Can be a group or a user */
-       public String getUserDisplayName(String dn) {
-               // FIXME: during initialisation phase, the system logs "admin" as user
-               // name rather than the corresponding dn
-               if ("admin".equals(dn))
-                       return "System Administrator";
-               else
-                       return UserAdminUtils.getUserDisplayName(getUserAdmin(), dn);
-       }
-
-       @Override
-       public String getUserMail(String dn) {
-               return UserAdminUtils.getUserMail(getUserAdmin(), dn);
-       }
-
-       /** Lists all roles of the given user */
-       @Override
-       public String[] getUserRoles(String dn) {
-               Authorization currAuth = getUserAdmin().getAuthorization(getUser(dn));
-               return currAuth.getRoles();
-       }
-
-       @Override
-       public boolean isUserInRole(String userDn, String roleDn) {
-               String[] roles = getUserRoles(userDn);
-               for (String role : roles) {
-                       if (role.equalsIgnoreCase(roleDn))
-                               return true;
-               }
-               return false;
-       }
-
-       public Set<User> listUsersInGroup(String groupDn, String filter) {
-               Group group = (Group) userAdmin.getRole(groupDn);
-               if (group == null)
-                       throw new IllegalArgumentException("Group " + groupDn + " not found");
-               Set<User> users = new HashSet<User>();
-               addUsers(users, group, filter);
-               return users;
-       }
-
-//     @Override
-//     public Set<User> listAccounts(HierarchyUnit hierarchyUnit, boolean deep) {
-//             if(!hierarchyUnit.isFunctional())
-//                     throw new IllegalArgumentException("Hierarchy unit "+hierarchyUnit.getBase()+" is not functional");
-//             UserDirectory directory = (UserDirectory)hierarchyUnit.getDirectory();
-//             Set<User> res = new HashSet<>();
-//             for(HierarchyUnit technicalHu:hierarchyUnit.getDirectHierarchyUnits(false)) {
-//                     if(technicalHu.isFunctional())
-//                             continue;
-//                     for(Role role:directory.getHierarchyUnitRoles(technicalHu, null, false)) {
-//                             if(role)
-//                     }
-//             }
-//             return res;
-//     }
-
-       /** Recursively add users to list */
-       private void addUsers(Set<User> users, Group group, String filter) {
-               Role[] roles = group.getMembers();
-               for (Role role : roles) {
-                       if (role.getType() == Role.GROUP) {
-                               addUsers(users, (Group) role, filter);
-                       } else if (role.getType() == Role.USER) {
-                               if (match(role, filter))
-                                       users.add((User) role);
-                       } else {
-                               // ignore
-                       }
-               }
-       }
-
-       public List<User> listGroups(String filter, boolean includeUsers, boolean includeSystemRoles) {
-               Role[] roles = null;
-               try {
-                       roles = getUserAdmin().getRoles(filter);
-               } catch (InvalidSyntaxException e) {
-                       throw new IllegalArgumentException("Unable to get roles with filter: " + filter, e);
-               }
-
-               List<User> users = new ArrayList<User>();
-               for (Role role : roles) {
-                       if ((includeUsers && role.getType() == Role.USER || role.getType() == Role.GROUP) && !users.contains(role)
-                                       && (includeSystemRoles
-                                                       || !role.getName().toLowerCase().endsWith(CmsConstants.SYSTEM_ROLES_BASEDN))) {
-                               if (match(role, filter))
-                                       users.add((User) role);
-                       }
-               }
-               return users;
-       }
-
-       private boolean match(Role role, String filter) {
-               boolean doFilter = filter != null && !"".equals(filter);
-               if (doFilter) {
-                       for (String prop : knownProps) {
-                               Object currProp = null;
-                               try {
-                                       currProp = role.getProperties().get(prop);
-                               } catch (Exception e) {
-                                       throw e;
-                               }
-                               if (currProp != null) {
-                                       String currPropStr = ((String) currProp).toLowerCase();
-                                       if (currPropStr.contains(filter.toLowerCase())) {
-                                               return true;
-                                       }
-                               }
-                       }
-                       return false;
-               } else
-                       return true;
-       }
-
-       @Override
-       public User getUserFromLocalId(String localId) {
-               User user = getUserAdmin().getUser(LdapAttrs.uid.name(), localId);
-               if (user == null)
-                       user = getUserAdmin().getUser(LdapAttrs.cn.name(), localId);
-               return user;
-       }
-
-       @Override
-       public String buildDefaultDN(String localId, int type) {
-               return buildDistinguishedName(localId, getDefaultDomainName(), type);
-       }
-
-       /*
-        * EDITION
-        */
-       @Override
-       public User createUser(String username, Map<String, Object> properties, Map<String, Object> credentials) {
-               try {
-                       userTransaction.begin();
-                       User user = (User) userAdmin.createRole(username, Role.USER);
-                       if (properties != null) {
-                               for (String key : properties.keySet())
-                                       user.getProperties().put(key, properties.get(key));
-                       }
-                       if (credentials != null) {
-                               for (String key : credentials.keySet())
-                                       user.getCredentials().put(key, credentials.get(key));
-                       }
-                       userTransaction.commit();
-                       return user;
-               } catch (Exception e) {
-                       try {
-                               userTransaction.rollback();
-                       } catch (Exception e1) {
-                               log.error("Could not roll back", e1);
-                       }
-                       if (e instanceof RuntimeException)
-                               throw (RuntimeException) e;
-                       else
-                               throw new RuntimeException("Cannot create user " + username, e);
-               }
-       }
-
-       @Override
-       public Group getOrCreateGroup(HierarchyUnit groups, String commonName) {
-               try {
-                       String dn = LdapAttrs.cn.name() + "=" + commonName + "," + groups.getBase();
-                       Group group = (Group) getUserAdmin().getRole(dn);
-                       if (group != null)
-                               return group;
-                       userTransaction.begin();
-                       group = (Group) userAdmin.createRole(dn, Role.GROUP);
-                       userTransaction.commit();
-                       return group;
-               } catch (Exception e) {
-                       try {
-                               userTransaction.rollback();
-                       } catch (Exception e1) {
-                               log.error("Could not roll back", e1);
-                       }
-                       if (e instanceof RuntimeException)
-                               throw (RuntimeException) e;
-                       else
-                               throw new RuntimeException("Cannot create group " + commonName + " in " + groups, e);
-               }
-       }
-
-       @Override
-       public Group getOrCreateSystemRole(HierarchyUnit roles, SystemRole systemRole) {
-               try {
-                       String dn = LdapAttrs.cn.name() + "=" + NamespaceUtils.toPrefixedName(systemRole.getName()) + ","
-                                       + roles.getBase();
-                       Group group = (Group) getUserAdmin().getRole(dn);
-                       if (group != null)
-                               return group;
-                       userTransaction.begin();
-                       group = (Group) userAdmin.createRole(dn, Role.GROUP);
-                       userTransaction.commit();
-                       return group;
-               } catch (Exception e) {
-                       try {
-                               userTransaction.rollback();
-                       } catch (Exception e1) {
-                               log.error("Could not roll back", e1);
-                       }
-                       if (e instanceof RuntimeException)
-                               throw (RuntimeException) e;
-                       else
-                               throw new RuntimeException("Cannot create system role " + systemRole + " in " + roles, e);
-               }
-       }
-
-       @Override
-       public HierarchyUnit getOrCreateHierarchyUnit(UserDirectory directory, String path) {
-               HierarchyUnit hi = directory.getHierarchyUnit(path);
-               if (hi != null)
-                       return hi;
-               try {
-                       userTransaction.begin();
-                       HierarchyUnit hierarchyUnit = directory.createHierarchyUnit(path);
-                       userTransaction.commit();
-                       return hierarchyUnit;
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot create hierarchy unit " + path + " in directory " + directory, e1);
-               }
-       }
-
-       @Override
-       public void addObjectClasses(Role role, Set<String> objectClasses, Map<String, Object> additionalProperties) {
-               try {
-                       userTransaction.begin();
-                       LdapEntry.addObjectClasses(role.getProperties(), objectClasses);
-                       for (String key : additionalProperties.keySet()) {
-                               role.getProperties().put(key, additionalProperties.get(key));
-                       }
-                       userTransaction.commit();
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot add object classes " + objectClasses + " to " + role, e1);
-               }
-       }
-
-       @Override
-       public void addObjectClasses(HierarchyUnit hierarchyUnit, Set<String> objectClasses,
-                       Map<String, Object> additionalProperties) {
-               try {
-                       userTransaction.begin();
-                       LdapEntry.addObjectClasses(hierarchyUnit.getProperties(), objectClasses);
-                       for (String key : additionalProperties.keySet()) {
-                               hierarchyUnit.getProperties().put(key, additionalProperties.get(key));
-                       }
-                       userTransaction.commit();
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot add object classes " + objectClasses + " to " + hierarchyUnit, e1);
-               }
-       }
-
-       @Override
-       public void edit(Runnable action) {
-               Objects.requireNonNull(action);
-               try {
-                       userTransaction.begin();
-                       action.run();
-                       userTransaction.commit();
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot edit", e1);
-               }
-       }
-
-       @Override
-       public void addMember(Group group, Role role) {
-               try {
-                       userTransaction.begin();
-                       group.addMember(role);
-                       userTransaction.commit();
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot add object classes " + role + " to group " + group, e1);
-               }
-       }
-
-       @Override
-       public String getDefaultDomainName() {
-               Map<String, String> dns = getKnownBaseDns(true);
-               if (dns.size() == 1)
-                       return dns.keySet().iterator().next();
-               else
-                       throw new IllegalStateException("Current context contains " + dns.size() + " base dns: "
-                                       + dns.keySet().toString() + ". Unable to chose a default one.");
-       }
-
-       public Map<String, String> getKnownBaseDns(boolean onlyWritable) {
-               Map<String, String> dns = new HashMap<String, String>();
-               for (UserDirectory userDirectory : userDirectories) {
-                       Boolean readOnly = userDirectory.isReadOnly();
-                       String baseDn = userDirectory.getBase();
-
-                       if (onlyWritable && readOnly)
-                               continue;
-                       if (baseDn.equalsIgnoreCase(CmsConstants.SYSTEM_ROLES_BASEDN))
-                               continue;
-                       if (baseDn.equalsIgnoreCase(CmsConstants.TOKENS_BASEDN))
-                               continue;
-                       dns.put(baseDn, DirectoryConf.propertiesAsUri(userDirectory.getProperties()).toString());
-
-               }
-               return dns;
-       }
-
-       public Set<UserDirectory> getUserDirectories() {
-               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getBase().compareTo(o2.getBase()));
-               res.addAll(userDirectories);
-               return res;
-       }
-
-       public String buildDistinguishedName(String localId, String baseDn, int type) {
-               Map<String, String> dns = getKnownBaseDns(true);
-               Dictionary<String, ?> props = DirectoryConf.uriAsProperties(dns.get(baseDn));
-               String dn = null;
-               if (Role.GROUP == type)
-                       dn = LdapAttrs.cn.name() + "=" + localId + "," + DirectoryConf.groupBase.getValue(props) + "," + baseDn;
-               else if (Role.USER == type)
-                       dn = LdapAttrs.uid.name() + "=" + localId + "," + DirectoryConf.userBase.getValue(props) + "," + baseDn;
-               else
-                       throw new IllegalStateException("Unknown role type. " + "Cannot deduce dn for " + localId);
-               return dn;
-       }
-
-       @Override
-       public void changeOwnPassword(char[] oldPassword, char[] newPassword) {
-               String name = CurrentUser.getUsername();
-               LdapName dn;
-               try {
-                       dn = new LdapName(name);
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Invalid user dn " + name, e);
-               }
-               User user = (User) userAdmin.getRole(dn.toString());
-               if (!user.hasCredential(null, oldPassword))
-                       throw new IllegalArgumentException("Invalid password");
-               if (Arrays.equals(newPassword, new char[0]))
-                       throw new IllegalArgumentException("New password empty");
-               try {
-                       userTransaction.begin();
-                       user.getCredentials().put(null, newPassword);
-                       userTransaction.commit();
-               } catch (Exception e) {
-                       try {
-                               userTransaction.rollback();
-                       } catch (Exception e1) {
-                               log.error("Could not roll back", e1);
-                       }
-                       if (e instanceof RuntimeException)
-                               throw (RuntimeException) e;
-                       else
-                               throw new RuntimeException("Cannot change password", e);
-               }
-       }
-
-       public void resetPassword(String username, char[] newPassword) {
-               LdapName dn;
-               try {
-                       dn = new LdapName(username);
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Invalid user dn " + username, e);
-               }
-               User user = (User) userAdmin.getRole(dn.toString());
-               if (Arrays.equals(newPassword, new char[0]))
-                       throw new IllegalArgumentException("New password empty");
-               try {
-                       userTransaction.begin();
-                       user.getCredentials().put(null, newPassword);
-                       userTransaction.commit();
-               } catch (Exception e) {
-                       try {
-                               userTransaction.rollback();
-                       } catch (Exception e1) {
-                               log.error("Could not roll back", e1);
-                       }
-                       if (e instanceof RuntimeException)
-                               throw (RuntimeException) e;
-                       else
-                               throw new RuntimeException("Cannot change password", e);
-               }
-       }
-
-       public String addSharedSecret(String email, int hours) {
-               User user = (User) userAdmin.getUser(LdapAttrs.mail.name(), email);
-               try {
-                       userTransaction.begin();
-                       String uuid = UUID.randomUUID().toString();
-                       SharedSecret sharedSecret = new SharedSecret(hours, uuid);
-                       user.getCredentials().put(SharedSecret.X_SHARED_SECRET, sharedSecret.toAuthPassword());
-                       String tokenStr = sharedSecret.getAuthInfo() + '$' + sharedSecret.getAuthValue();
-                       userTransaction.commit();
-                       return tokenStr;
-               } catch (Exception e) {
-                       try {
-                               userTransaction.rollback();
-                       } catch (Exception e1) {
-                               log.error("Could not roll back", e1);
-                       }
-                       if (e instanceof RuntimeException)
-                               throw (RuntimeException) e;
-                       else
-                               throw new RuntimeException("Cannot change password", e);
-               }
-       }
-
-       @Deprecated
-       public String addSharedSecret(String username, String authInfo, String authToken) {
-               try {
-                       userTransaction.begin();
-                       User user = (User) userAdmin.getRole(username);
-                       SharedSecret sharedSecret = new SharedSecret(authInfo, authToken);
-                       user.getCredentials().put(SharedSecret.X_SHARED_SECRET, sharedSecret.toAuthPassword());
-                       String tokenStr = sharedSecret.getAuthInfo() + '$' + sharedSecret.getAuthValue();
-                       userTransaction.commit();
-                       return tokenStr;
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot add shared secret", e1);
-               }
-       }
-
-       @Override
-       public void expireAuthToken(String token) {
-               try {
-                       userTransaction.begin();
-                       String dn = cn + "=" + token + "," + CmsConstants.TOKENS_BASEDN;
-                       Group tokenGroup = (Group) userAdmin.getRole(dn);
-                       String ldapDate = NamingUtils.instantToLdapDate(ZonedDateTime.now(ZoneOffset.UTC));
-                       tokenGroup.getProperties().put(description.name(), ldapDate);
-                       userTransaction.commit();
-                       if (log.isDebugEnabled())
-                               log.debug("Token " + token + " expired.");
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot expire token", e1);
-               }
-       }
-
-       @Override
-       public void expireAuthTokens(Subject subject) {
-               Set<String> tokens = TokenUtils.tokensUsed(subject, CmsConstants.TOKENS_BASEDN);
-               for (String token : tokens)
-                       expireAuthToken(token);
-       }
-
-       @Override
-       public void addAuthToken(String userDn, String token, Integer hours, String... roles) {
-               addAuthToken(userDn, token, ZonedDateTime.now().plusHours(hours), roles);
-       }
-
-       @Override
-       public void addAuthToken(String userDn, String token, ZonedDateTime expiryDate, String... roles) {
-               try {
-                       userTransaction.begin();
-                       User user = (User) userAdmin.getRole(userDn);
-                       String tokenDn = cn + "=" + token + "," + CmsConstants.TOKENS_BASEDN;
-                       Group tokenGroup = (Group) userAdmin.createRole(tokenDn, Role.GROUP);
-                       if (roles != null)
-                               for (String role : roles) {
-                                       Role r = userAdmin.getRole(role);
-                                       if (r != null)
-                                               tokenGroup.addMember(r);
-                                       else {
-                                               if (!role.equals(CmsConstants.ROLE_USER)) {
-                                                       throw new IllegalStateException(
-                                                                       "Cannot add role " + role + " to token " + token + " for " + userDn);
-                                               }
-                                       }
-                               }
-                       tokenGroup.getProperties().put(owner.name(), user.getName());
-                       if (expiryDate != null) {
-                               String ldapDate = NamingUtils.instantToLdapDate(expiryDate);
-                               tokenGroup.getProperties().put(description.name(), ldapDate);
-                       }
-                       userTransaction.commit();
-               } catch (Exception e1) {
-                       try {
-                               if (!userTransaction.isNoTransactionStatus())
-                                       userTransaction.rollback();
-                       } catch (Exception e2) {
-                               if (log.isTraceEnabled())
-                                       log.trace("Cannot rollback transaction", e2);
-                       }
-                       throw new RuntimeException("Cannot add token", e1);
-               }
-       }
-
-       @Override
-       public UserDirectory getDirectory(Role user) {
-               String name = user.getName();
-               NavigableMap<String, UserDirectory> possible = new TreeMap<>();
-               for (UserDirectory userDirectory : userDirectories) {
-                       if (name.endsWith(userDirectory.getBase())) {
-                               possible.put(userDirectory.getBase(), userDirectory);
-                       }
-               }
-               if (possible.size() == 0)
-                       throw new IllegalStateException("No user directory found for user " + name);
-               return possible.lastEntry().getValue();
-       }
-
-//     public User createUserFromPerson(Node person) {
-//             String email = JcrUtils.get(person, LdapAttrs.mail.property());
-//             String dn = buildDefaultDN(email, Role.USER);
-//             User user;
-//             try {
-//                     userTransaction.begin();
-//                     user = (User) userAdmin.createRole(dn, Role.USER);
-//                     Dictionary<String, Object> userProperties = user.getProperties();
-//                     String name = JcrUtils.get(person, LdapAttrs.displayName.property());
-//                     userProperties.put(LdapAttrs.cn.name(), name);
-//                     userProperties.put(LdapAttrs.displayName.name(), name);
-//                     String givenName = JcrUtils.get(person, LdapAttrs.givenName.property());
-//                     String surname = JcrUtils.get(person, LdapAttrs.sn.property());
-//                     userProperties.put(LdapAttrs.givenName.name(), givenName);
-//                     userProperties.put(LdapAttrs.sn.name(), surname);
-//                     userProperties.put(LdapAttrs.mail.name(), email.toLowerCase());
-//                     userTransaction.commit();
-//             } catch (Exception e) {
-//                     try {
-//                             userTransaction.rollback();
-//                     } catch (Exception e1) {
-//                             log.error("Could not roll back", e1);
-//                     }
-//                     if (e instanceof RuntimeException)
-//                             throw (RuntimeException) e;
-//                     else
-//                             throw new RuntimeException("Cannot create user", e);
-//             }
-//             return user;
-//     }
-
-       public UserAdmin getUserAdmin() {
-               return userAdmin;
-       }
-
-//     public UserTransaction getUserTransaction() {
-//             return userTransaction;
-//     }
-
-       /* DEPENDENCY INJECTION */
-       public void setUserAdmin(UserAdmin userAdmin) {
-               this.userAdmin = userAdmin;
-
-               if (userAdmin instanceof AggregatingUserAdmin) {
-                       userDirectories = ((AggregatingUserAdmin) userAdmin).getUserDirectories();
-               } else {
-                       throw new IllegalArgumentException("Only " + AggregatingUserAdmin.class.getName() + " is supported.");
-               }
-
-//             this.serviceProperties = serviceProperties;
-       }
-
-       public void setUserTransaction(WorkTransaction userTransaction) {
-               this.userTransaction = userTransaction;
-       }
-
-//     public void addUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
-//             userDirectories.put(userDirectory, new Hashtable<>(properties));
-//     }
-//
-//     public void removeUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
-//             userDirectories.remove(userDirectory);
-//     }
-
-}
index 73f474637750a2f61aa825cddbdc0d12861df99e..9e0ebce97d230ec24828ccbbb548786855013ae6 100644 (file)
@@ -1,16 +1,12 @@
 package org.argeo.cms.internal.auth;
 
-import static org.argeo.api.acr.RuntimeNamespaceContext.getNamespaceContext;
-
 import java.security.Principal;
 import java.util.HashSet;
 import java.util.Set;
 
 import javax.xml.namespace.QName;
 
-import org.argeo.api.acr.CrName;
-import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.cms.auth.RoleNameUtils;
+import org.argeo.cms.RoleNameUtils;
 import org.osgi.service.useradmin.Authorization;
 
 /**
@@ -23,71 +19,25 @@ import org.osgi.service.useradmin.Authorization;
  */
 public final class ImpliedByPrincipal implements Principal {
        private final String name;
-       private Set<Principal> causes = new HashSet<Principal>();
-
-       private QName roleName;
-//     private int type = Role.ROLE;
+       private final QName roleName;
+       private final boolean systemRole;
+       private final String context;
 
-       private boolean systemRole = false;
-       private String context;
+       private Set<Principal> causes = new HashSet<Principal>();
 
        public ImpliedByPrincipal(String name, Principal userPrincipal) {
                this.name = name;
-               String cn = RoleNameUtils.getLastRdnValue(name);
-               roleName = NamespaceUtils.parsePrefixedName(getNamespaceContext(), cn);
-               if (roleName.getNamespaceURI().equals(CrName.ROLE_NAMESPACE_URI)) {
-                       systemRole = true;
-               }
+               roleName = RoleNameUtils.getLastRdnAsName(name);
+               systemRole = RoleNameUtils.isSystemRole(roleName);
                context = RoleNameUtils.getContext(name);
-//             try {
-//                     this.name = new LdapName(name);
-//             } catch (InvalidNameException e) {
-//                     throw new IllegalArgumentException("Badly formatted role name", e);
-//             }
                if (userPrincipal != null)
                        causes.add(userPrincipal);
        }
 
-//     public ImpliedByPrincipal(LdapName name, Principal userPrincipal) {
-//             this.name = name;
-//             if (userPrincipal != null)
-//                     causes.add(userPrincipal);
-//     }
-
        public String getName() {
                return name;
        }
 
-       /*
-        * USER ADMIN
-        */
-//     public boolean addMember(Principal user) {
-//             throw new UnsupportedOperationException();
-//     }
-//
-//     public boolean removeMember(Principal user) {
-//             throw new UnsupportedOperationException();
-//     }
-//
-//     public boolean isMember(Principal member) {
-//             return causes.contains(member);
-//     }
-//
-//     public Enumeration<? extends Principal> members() {
-//             return Collections.enumeration(causes);
-//     }
-//
-//
-//     /** Type of {@link Role}, if known. */
-//     public int getType() {
-//             return type;
-//     }
-//
-//     /** Not supported for the time being. */
-//     public Dictionary<String, Object> getProperties() {
-//             throw new UnsupportedOperationException();
-//     }
-
        /*
         * OBJECT
         */
@@ -111,8 +61,6 @@ public final class ImpliedByPrincipal implements Principal {
 
        @Override
        public boolean equals(Object obj) {
-               // if (this == obj)
-               // return true;
                if (obj instanceof ImpliedByPrincipal) {
                        ImpliedByPrincipal that = (ImpliedByPrincipal) obj;
                        // TODO check members too?
@@ -123,7 +71,6 @@ public final class ImpliedByPrincipal implements Principal {
 
        @Override
        public String toString() {
-               // return name.toString() + " implied by " + causes;
                return name.toString();
        }
 }
index 164e9b9b2b24245f913773796d661fc362409a63..e17a089fe05e15db48924216a5f3f6c1f998b2c1 100644 (file)
@@ -5,7 +5,7 @@ import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 
 import org.argeo.api.cms.CmsAuth;
-import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.auth.RemoteAuthCallbackHandler;
 import org.argeo.cms.auth.RemoteAuthRequest;
 import org.argeo.cms.auth.RemoteAuthResponse;
@@ -15,20 +15,14 @@ import com.sun.net.httpserver.Authenticator;
 import com.sun.net.httpserver.HttpExchange;
 import com.sun.net.httpserver.HttpPrincipal;
 
+/** An {@link Authenticator} implementation based on CMS authentication. */
 public class CmsAuthenticator extends Authenticator {
-//     final static String HEADER_AUTHORIZATION = "Authorization";
-//     final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
-
-//     private final static CmsLog log = CmsLog.getLog(CmsAuthenticator.class);
-
        // TODO make it configurable
        private final String httpAuthRealm = "Argeo";
        private final boolean forceBasic = false;
 
        @Override
        public Result authenticate(HttpExchange exch) {
-//             if (log.isTraceEnabled())
-//                     HttpUtils.logRequestHeaders(log, request);
                RemoteAuthHttpExchange remoteAuthExchange = new RemoteAuthHttpExchange(exch);
                ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader();
                Thread.currentThread().setContextClassLoader(CmsAuthenticator.class.getClassLoader());
@@ -53,20 +47,6 @@ public class CmsAuthenticator extends Authenticator {
 
                Subject subject = lc.getSubject();
 
-//             CurrentSubject.callAs(subject, () -> {
-//                     RemoteAuthUtils.configureRequestSecurity(remoteAuthExchange);
-//                     return null;
-//             });
-//             Subject.doAs(subject, new PrivilegedAction<Void>() {
-//
-//                     @Override
-//                     public Void run() {
-//                             // TODO also set login context in order to log out ?
-//                             RemoteAuthUtils.configureRequestSecurity(new ServletHttpRequest(request));
-//                             return null;
-//                     }
-//
-//             });
                String username = CurrentUser.getUsername(subject);
                HttpPrincipal httpPrincipal = new HttpPrincipal(username, httpAuthRealm);
                return new Authenticator.Success(httpPrincipal);
index 00f2b8fe1646dac38053a2125743c5bed9ac4f90..b7e670c7943899cb085a1601c0485ffd99c243ea 100644 (file)
@@ -1,5 +1,6 @@
 package org.argeo.cms.internal.http;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -22,8 +23,14 @@ public class RemoteAuthHttpExchange implements RemoteAuthRequest, RemoteAuthResp
        }
 
        @Override
-       public void setHeader(String keys, String value) {
-               httpExchange.getResponseHeaders().put(keys, Collections.singletonList(value));
+       public void setHeader(String headerName, String value) {
+               httpExchange.getResponseHeaders().put(headerName, Collections.singletonList(value));
+       }
+
+       @Override
+       public void addHeader(String headerName, String value) {
+               List<String> values = httpExchange.getResponseHeaders().getOrDefault(headerName, new ArrayList<>());
+               values.add(value);
        }
 
        @Override
index 59b226a53c61a284ade9a84288cb373c6048831c..b09956203cc2eb4afa0bfa60b2a1c22cf1fe9f5c 100644 (file)
@@ -26,29 +26,7 @@ public class CmsActivator implements BundleActivator {
 
        private static BundleContext bundleContext;
 
-//     private LogReaderService logReaderService;
-//
-//     private CmsOsgiLogger logger;
-
        void init() {
-//             Runtime.getRuntime().addShutdownHook(new CmsShutdown());
-//             instance = this;
-//             this.bc = bundleContext;
-//             if (bundleContext != null)
-//                     this.logReaderService = getService(LogReaderService.class);
-//             initArgeoLogger();
-//             this.internalExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
-//
-//             try {
-//                     initSecurity();
-////                   initArgeoLogger();
-//                     initNode();
-//
-//                     if (log.isTraceEnabled())
-//                             log.trace("Kernel bundle started");
-//             } catch (Throwable e) {
-//                     log.error("## FATAL: CMS activator failed", e);
-//             }
        }
 
        void destroy() {
@@ -98,12 +76,6 @@ public class CmsActivator implements BundleActivator {
 
        }
 
-//     private void initArgeoLogger() {
-//             logger = new CmsOsgiLogger(logReaderService);
-//             if (bundleContext != null)
-//                     bundleContext.registerService(ArgeoLogger.class, logger, null);
-//     }
-
        public static <T> void registerService(Class<T> clss, T service, Dictionary<String, ?> properties) {
                if (bundleContext != null) {
                        bundleContext.registerService(clss, service, properties);
index 3358ed82574eb53562c955f6a9111ebf82c74aff..85f045bae660b6783d2aa4448e7fdce59af327e1 100644 (file)
@@ -5,7 +5,7 @@ import java.util.Enumeration;
 
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsLog;
-import org.argeo.util.directory.DirectoryConf;
+import org.argeo.cms.runtime.DirectoryConf;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
index c36f410e2ac6fa115292396e4db3e69b0066d8d2..c80933a559753203cac8e50ebc95b98afd79fd42 100644 (file)
@@ -25,9 +25,9 @@ import org.argeo.cms.dav.DavDepth;
 import org.argeo.cms.dav.DavHttpHandler;
 import org.argeo.cms.dav.DavPropfind;
 import org.argeo.cms.dav.DavResponse;
+import org.argeo.cms.http.HttpStatus;
 import org.argeo.cms.internal.http.RemoteAuthHttpExchange;
-import org.argeo.util.StreamUtils;
-import org.argeo.util.http.HttpStatus;
+import org.argeo.cms.util.StreamUtils;
 
 import com.sun.net.httpserver.HttpExchange;
 
index c2d2ccf42d4cdd2814e6c4806d366bf9385d935d..bd54b20594b5e7200d0a3e04f975e8cfc13ab354 100644 (file)
@@ -25,19 +25,18 @@ import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.ietf.jgss.GSSCredential;
 import org.osgi.service.useradmin.UserAdmin;
 
+/** Reference implementation of {@link CmsContext}. */
 public class CmsContextImpl implements CmsContext {
 
        private final CmsLog log = CmsLog.getLog(getClass());
 
        private static CompletableFuture<CmsContextImpl> instance = new CompletableFuture<CmsContextImpl>();
-//     private static CmsContextImpl instance = null;
 
        private CmsState cmsState;
        private CmsDeployment cmsDeployment;
        private UserAdmin userAdmin;
        private UuidFactory uuidFactory;
        private CmsEventBus cmsEventBus;
-//     private ProvidedRepository contentRepository;
 
        // i18n
        private Locale defaultLocale;
@@ -64,9 +63,6 @@ public class CmsContextImpl implements CmsContext {
                                }
                        }
                }, "Check readiness").start();
-
-               // checkReadiness();
-
                setInstance(this);
        }
 
@@ -178,14 +174,6 @@ public class CmsContextImpl implements CmsContext {
                this.uuidFactory = uuidFactory;
        }
 
-//     public ProvidedRepository getContentRepository() {
-//             return contentRepository;
-//     }
-//
-//     public void setContentRepository(ProvidedRepository contentRepository) {
-//             this.contentRepository = contentRepository;
-//     }
-
        @Override
        public Locale getDefaultLocale() {
                return defaultLocale;
@@ -238,15 +226,6 @@ public class CmsContextImpl implements CmsContext {
        }
 
        private static void setInstance(CmsContextImpl cmsContextImpl) {
-//             if (cmsContextImpl != null) {
-//                     if (instance != null)
-//                             throw new IllegalStateException("CMS Context is already set");
-//                     instance = cmsContextImpl;
-//             } else {
-//                     instance = null;
-//             }
-//             CmsContextImpl.class.notifyAll();
-
                if (cmsContextImpl != null) {
                        if (instance.isDone())
                                throw new IllegalStateException("CMS Context is already set");
@@ -259,15 +238,6 @@ public class CmsContextImpl implements CmsContext {
        }
 
        private static CmsContextImpl getInstance() {
-//             while (instance == null) {
-//                     try {
-//                             CmsContextImpl.class.wait();
-//                     } catch (InterruptedException e) {
-//                             throw new IllegalStateException("Cannot wait for CMS context instance", e);
-//                     }
-//             }
-//             return instance;
-
                try {
                        return instance.get();
                } catch (InterruptedException | ExecutionException e) {
index 421ff661aeb2decf812a3f9a2baec23a4ebbd31b..e2d1fb97a592d38e6a64e85918353dbb5b49ce6a 100644 (file)
@@ -18,7 +18,7 @@ import com.sun.net.httpserver.HttpContext;
 import com.sun.net.httpserver.HttpHandler;
 import com.sun.net.httpserver.HttpServer;
 
-/** Implementation of a CMS deployment. */
+/** Reference implementation of {@link CmsDeployment}. */
 public class CmsDeploymentImpl implements CmsDeployment {
        private final CmsLog log = CmsLog.getLog(getClass());
 
index eaa63756dc05e61800ffdb8668bf4ba200907ff3..99f6c1d8d18a548d6ecb6adfff5b6fd91abf5325 100644 (file)
@@ -10,16 +10,12 @@ import org.argeo.api.cms.CmsEventBus;
 import org.argeo.api.cms.CmsEventSubscriber;
 import org.argeo.api.cms.CmsLog;
 
+/** {@link CmsEventBus} implementation based on {@link Flow}. */
 public class CmsEventBusImpl implements CmsEventBus {
        private final CmsLog log = CmsLog.getLog(CmsEventBus.class);
 
-       // CMS events
        private Map<String, SubmissionPublisher<Map<String, Object>>> topics = new TreeMap<>();
-//     private IdentityHashMap<CmsEventSubscriber, List<CmsEventFlowSubscriber>> subscriptions = new IdentityHashMap<>();
 
-       /*
-        * CMS Events
-        */
        @Override
        public void sendEvent(String topic, Map<String, Object> event) {
                SubmissionPublisher<Map<String, Object>> publisher = topics.get(topic);
@@ -58,6 +54,7 @@ public class CmsEventBusImpl implements CmsEventBus {
                }
        }
 
+       /** A subscriber to a topic. */
        static class CmsEventFlowSubscriber implements Flow.Subscriber<Map<String, Object>> {
                private String topic;
                private CmsEventSubscriber eventSubscriber;
index cb806444fc668c3e5508263de895e376b741f924..5c3838a0a3134a4a6e24e202ecd20e0c992e8711 100644 (file)
@@ -38,7 +38,7 @@ import org.argeo.api.cms.CmsState;
 import org.argeo.api.uuid.UuidFactory;
 import org.argeo.cms.CmsDeployProperty;
 import org.argeo.cms.auth.ident.IdentClient;
-import org.argeo.util.FsUtils;
+import org.argeo.cms.util.FsUtils;
 
 /**
  * Implementation of a {@link CmsState}, initialising the required services.
@@ -170,9 +170,11 @@ public class CmsStateImpl implements CmsState {
                        posixPermissions.add(PosixFilePermission.OWNER_WRITE);
                        posixPermissions.add(PosixFilePermission.OWNER_EXECUTE);
                        try {
+                               if (!Files.exists(privateDir))
+                                       Files.createDirectories(privateDir);
                                Files.setPosixFilePermissions(privateDir, posixPermissions);
                        } catch (IOException e) {
-                               log.error("Cannot set permissions on " + privateDir);
+                               log.error("Cannot set permissions on " + privateDir, e);
                        }
                }
 
index 7f4314b996bc9a0c9d7c5f8042c10445fbaf81e2..e6f903d393179003f2862331a9ab131f0133de11 100644 (file)
@@ -29,14 +29,14 @@ import org.argeo.api.cms.CmsAuth;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsState;
+import org.argeo.api.cms.directory.UserDirectory;
+import org.argeo.api.cms.transaction.WorkControl;
+import org.argeo.api.cms.transaction.WorkTransaction;
 import org.argeo.cms.CmsDeployProperty;
-import org.argeo.osgi.useradmin.AggregatingUserAdmin;
-import org.argeo.osgi.useradmin.DirectoryUserAdmin;
-import org.argeo.osgi.useradmin.UserDirectory;
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.naming.dns.DnsBrowser;
-import org.argeo.util.transaction.WorkControl;
-import org.argeo.util.transaction.WorkTransaction;
+import org.argeo.cms.dns.DnsBrowser;
+import org.argeo.cms.osgi.useradmin.AggregatingUserAdmin;
+import org.argeo.cms.osgi.useradmin.DirectoryUserAdmin;
+import org.argeo.cms.runtime.DirectoryConf;
 import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSManager;
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserManagerImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserManagerImpl.java
new file mode 100644 (file)
index 0000000..1eb227b
--- /dev/null
@@ -0,0 +1,755 @@
+package org.argeo.cms.internal.runtime;
+
+import static org.argeo.api.acr.ldap.LdapAttr.cn;
+import static org.argeo.api.acr.ldap.LdapAttr.description;
+import static org.argeo.api.acr.ldap.LdapAttr.owner;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.Subject;
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.acr.ldap.NamingUtils;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.directory.CmsGroup;
+import org.argeo.api.cms.directory.CmsUser;
+import org.argeo.api.cms.directory.CmsUserManager;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.UserDirectory;
+import org.argeo.api.cms.transaction.WorkTransaction;
+import org.argeo.cms.CurrentUser;
+import org.argeo.cms.auth.UserAdminUtils;
+import org.argeo.cms.directory.ldap.LdapEntry;
+import org.argeo.cms.directory.ldap.SharedSecret;
+import org.argeo.cms.osgi.useradmin.AggregatingUserAdmin;
+import org.argeo.cms.osgi.useradmin.TokenUtils;
+import org.argeo.cms.runtime.DirectoryConf;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Canonical implementation of the people {@link CmsUserManager}. Wraps
+ * interaction with users and groups.
+ * 
+ * In a *READ-ONLY* mode. We want to be able to:
+ * <ul>
+ * <li>Retrieve my user and corresponding information (main info,
+ * groups...)</li>
+ * <li>List all local groups (not the system roles)</li>
+ * <li>If sufficient rights: retrieve a given user and its information</li>
+ * </ul>
+ */
+public class CmsUserManagerImpl implements CmsUserManager {
+       private final static CmsLog log = CmsLog.getLog(CmsUserManagerImpl.class);
+
+       private UserAdmin userAdmin;
+//     private Map<String, String> serviceProperties;
+       private WorkTransaction userTransaction;
+
+       private final String[] knownProps = { LdapAttr.cn.name(), LdapAttr.sn.name(), LdapAttr.givenName.name(),
+                       LdapAttr.uid.name() };
+
+//     private Map<UserDirectory, Hashtable<String, Object>> userDirectories = Collections
+//                     .synchronizedMap(new LinkedHashMap<>());
+
+       private Set<UserDirectory> userDirectories = new HashSet<>();
+
+       public void start() {
+               log.debug(() -> "CMS user manager available");
+       }
+
+       public void stop() {
+
+       }
+
+       @Override
+       public String getMyMail() {
+               return getUserMail(CurrentUser.getUsername());
+       }
+
+       @Override
+       public Role[] getRoles(String filter) {
+               try {
+                       return userAdmin.getRoles(filter);
+               } catch (InvalidSyntaxException e) {
+                       throw new IllegalArgumentException("Invalid filter " + filter, e);
+               }
+       }
+
+       // ALL USER: WARNING access to this will be later reduced
+
+       /** Retrieve a user given his dn, or <code>null</code> if it doesn't exist. */
+       public CmsUser getUser(String dn) {
+               return (CmsUser) getUserAdmin().getRole(dn);
+       }
+
+       /** Can be a group or a user */
+       public String getUserDisplayName(String dn) {
+               // FIXME: during initialisation phase, the system logs "admin" as user
+               // name rather than the corresponding dn
+               if ("admin".equals(dn))
+                       return "System Administrator";
+               else
+                       return UserAdminUtils.getUserDisplayName(getUserAdmin(), dn);
+       }
+
+       @Override
+       public String getUserMail(String dn) {
+               return UserAdminUtils.getUserMail(getUserAdmin(), dn);
+       }
+
+       /** Lists all roles of the given user */
+       @Override
+       public String[] getUserRoles(String dn) {
+               Authorization currAuth = getUserAdmin().getAuthorization(getUser(dn));
+               return currAuth.getRoles();
+       }
+
+       @Override
+       public boolean isUserInRole(String userDn, String roleDn) {
+               String[] roles = getUserRoles(userDn);
+               for (String role : roles) {
+                       if (role.equalsIgnoreCase(roleDn))
+                               return true;
+               }
+               return false;
+       }
+
+       public Set<CmsUser> listUsersInGroup(String groupDn, String filter) {
+               Group group = (Group) userAdmin.getRole(groupDn);
+               if (group == null)
+                       throw new IllegalArgumentException("Group " + groupDn + " not found");
+               Set<CmsUser> users = new HashSet<>();
+               addUsers(users, group, filter);
+               return users;
+       }
+
+//     @Override
+//     public Set<User> listAccounts(HierarchyUnit hierarchyUnit, boolean deep) {
+//             if(!hierarchyUnit.isFunctional())
+//                     throw new IllegalArgumentException("Hierarchy unit "+hierarchyUnit.getBase()+" is not functional");
+//             UserDirectory directory = (UserDirectory)hierarchyUnit.getDirectory();
+//             Set<User> res = new HashSet<>();
+//             for(HierarchyUnit technicalHu:hierarchyUnit.getDirectHierarchyUnits(false)) {
+//                     if(technicalHu.isFunctional())
+//                             continue;
+//                     for(Role role:directory.getHierarchyUnitRoles(technicalHu, null, false)) {
+//                             if(role)
+//                     }
+//             }
+//             return res;
+//     }
+
+       /** Recursively add users to list */
+       private void addUsers(Set<CmsUser> users, Group group, String filter) {
+               Role[] roles = group.getMembers();
+               for (Role role : roles) {
+                       if (role.getType() == Role.GROUP) {
+                               addUsers(users, (CmsGroup) role, filter);
+                       } else if (role.getType() == Role.USER) {
+                               if (match(role, filter))
+                                       users.add((CmsUser) role);
+                       } else {
+                               // ignore
+                       }
+               }
+       }
+
+       public List<CmsUser> listGroups(String filter, boolean includeUsers, boolean includeSystemRoles) {
+               Role[] roles = null;
+               try {
+                       roles = getUserAdmin().getRoles(filter);
+               } catch (InvalidSyntaxException e) {
+                       throw new IllegalArgumentException("Unable to get roles with filter: " + filter, e);
+               }
+
+               List<CmsUser> users = new ArrayList<>();
+               for (Role role : roles) {
+                       if ((includeUsers && role.getType() == Role.USER || role.getType() == Role.GROUP) && !users.contains(role)
+                                       && (includeSystemRoles
+                                                       || !role.getName().toLowerCase().endsWith(CmsConstants.SYSTEM_ROLES_BASEDN))) {
+                               if (match(role, filter))
+                                       users.add((CmsUser) role);
+                       }
+               }
+               return users;
+       }
+
+       private boolean match(Role role, String filter) {
+               boolean doFilter = filter != null && !"".equals(filter);
+               if (doFilter) {
+                       for (String prop : knownProps) {
+                               Object currProp = null;
+                               try {
+                                       currProp = role.getProperties().get(prop);
+                               } catch (Exception e) {
+                                       throw e;
+                               }
+                               if (currProp != null) {
+                                       String currPropStr = ((String) currProp).toLowerCase();
+                                       if (currPropStr.contains(filter.toLowerCase())) {
+                                               return true;
+                                       }
+                               }
+                       }
+                       return false;
+               } else
+                       return true;
+       }
+
+       @Override
+       public CmsUser getUserFromLocalId(String localId) {
+               CmsUser user = (CmsUser) getUserAdmin().getUser(LdapAttr.uid.name(), localId);
+               if (user == null)
+                       user = (CmsUser) getUserAdmin().getUser(LdapAttr.cn.name(), localId);
+               return user;
+       }
+
+       @Override
+       public String buildDefaultDN(String localId, int type) {
+               return buildDistinguishedName(localId, getDefaultDomainName(), type);
+       }
+
+       /*
+        * EDITION
+        */
+       @Override
+       public CmsUser createUser(String username, Map<String, Object> properties, Map<String, Object> credentials) {
+               try {
+                       userTransaction.begin();
+                       CmsUser user = (CmsUser) userAdmin.createRole(username, Role.USER);
+                       if (properties != null) {
+                               for (String key : properties.keySet())
+                                       user.getProperties().put(key, properties.get(key));
+                       }
+                       if (credentials != null) {
+                               for (String key : credentials.keySet())
+                                       user.getCredentials().put(key, credentials.get(key));
+                       }
+                       userTransaction.commit();
+                       return user;
+               } catch (Exception e) {
+                       try {
+                               userTransaction.rollback();
+                       } catch (Exception e1) {
+                               log.error("Could not roll back", e1);
+                       }
+                       if (e instanceof RuntimeException)
+                               throw (RuntimeException) e;
+                       else
+                               throw new RuntimeException("Cannot create user " + username, e);
+               }
+       }
+
+       @Override
+       public CmsGroup createGroup(String dn) {
+               try {
+                       userTransaction.begin();
+                       CmsGroup group = (CmsGroup) userAdmin.createRole(dn, Role.GROUP);
+                       userTransaction.commit();
+                       return group;
+               } catch (Exception e) {
+                       try {
+                               userTransaction.rollback();
+                       } catch (Exception e1) {
+                               log.error("Could not roll back", e1);
+                       }
+                       if (e instanceof RuntimeException)
+                               throw (RuntimeException) e;
+                       else
+                               throw new RuntimeException("Cannot create group " + dn, e);
+               }
+       }
+
+       @Override
+       public CmsGroup getOrCreateGroup(HierarchyUnit groups, String commonName) {
+               String dn = LdapAttr.cn.name() + "=" + commonName + "," + groups.getBase();
+               CmsGroup group = (CmsGroup) getUserAdmin().getRole(dn);
+               if (group != null)
+                       return group;
+               try {
+                       userTransaction.begin();
+                       group = (CmsGroup) userAdmin.createRole(dn, Role.GROUP);
+                       userTransaction.commit();
+                       return group;
+               } catch (Exception e) {
+                       try {
+                               userTransaction.rollback();
+                       } catch (Exception e1) {
+                               log.error("Could not roll back", e1);
+                       }
+                       if (e instanceof RuntimeException)
+                               throw (RuntimeException) e;
+                       else
+                               throw new RuntimeException("Cannot create group " + commonName + " in " + groups, e);
+               }
+       }
+
+       @Override
+       public CmsGroup getOrCreateSystemRole(HierarchyUnit roles, QName systemRole) {
+               String dn = LdapAttr.cn.name() + "=" + NamespaceUtils.toPrefixedName(systemRole) + "," + roles.getBase();
+               CmsGroup group = (CmsGroup) getUserAdmin().getRole(dn);
+               if (group != null)
+                       return group;
+               try {
+                       userTransaction.begin();
+                       group = (CmsGroup) userAdmin.createRole(dn, Role.GROUP);
+                       userTransaction.commit();
+                       return group;
+               } catch (Exception e) {
+                       try {
+                               userTransaction.rollback();
+                       } catch (Exception e1) {
+                               log.error("Could not roll back", e1);
+                       }
+                       if (e instanceof RuntimeException)
+                               throw (RuntimeException) e;
+                       else
+                               throw new RuntimeException("Cannot create system role " + systemRole + " in " + roles, e);
+               }
+       }
+
+       @Override
+       public HierarchyUnit getOrCreateHierarchyUnit(UserDirectory directory, String path) {
+               HierarchyUnit hi = directory.getHierarchyUnit(path);
+               if (hi != null)
+                       return hi;
+               try {
+                       userTransaction.begin();
+                       HierarchyUnit hierarchyUnit = directory.createHierarchyUnit(path);
+                       userTransaction.commit();
+                       return hierarchyUnit;
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot create hierarchy unit " + path + " in directory " + directory, e1);
+               }
+       }
+
+       @Override
+       public void addObjectClasses(Role role, Set<String> objectClasses, Map<String, Object> additionalProperties) {
+               try {
+                       userTransaction.begin();
+                       LdapEntry.addObjectClasses(role.getProperties(), objectClasses);
+                       for (String key : additionalProperties.keySet()) {
+                               role.getProperties().put(key, additionalProperties.get(key));
+                       }
+                       userTransaction.commit();
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot add object classes " + objectClasses + " to " + role, e1);
+               }
+       }
+
+       @Override
+       public void addObjectClasses(HierarchyUnit hierarchyUnit, Set<String> objectClasses,
+                       Map<String, Object> additionalProperties) {
+               try {
+                       userTransaction.begin();
+                       LdapEntry.addObjectClasses(hierarchyUnit.getProperties(), objectClasses);
+                       for (String key : additionalProperties.keySet()) {
+                               hierarchyUnit.getProperties().put(key, additionalProperties.get(key));
+                       }
+                       userTransaction.commit();
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot add object classes " + objectClasses + " to " + hierarchyUnit, e1);
+               }
+       }
+
+       @Override
+       public void edit(Runnable action) {
+               Objects.requireNonNull(action);
+               try {
+                       userTransaction.begin();
+                       action.run();
+                       userTransaction.commit();
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot edit", e1);
+               }
+       }
+
+       @Override
+       public void addMember(CmsGroup group, Role role) {
+               try {
+                       userTransaction.begin();
+                       group.addMember(role);
+                       userTransaction.commit();
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot add member " + role + " to group " + group, e1);
+               }
+       }
+
+       @Override
+       public void removeMember(CmsGroup group, Role role) {
+               try {
+                       userTransaction.begin();
+                       group.removeMember(role);
+                       userTransaction.commit();
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot remove member " + role + " from group " + group, e1);
+               }
+       }
+
+       @Override
+       public String getDefaultDomainName() {
+               Map<String, String> dns = getKnownBaseDns(true);
+               if (dns.size() == 1)
+                       return dns.keySet().iterator().next();
+               else
+                       throw new IllegalStateException("Current context contains " + dns.size() + " base dns: "
+                                       + dns.keySet().toString() + ". Unable to chose a default one.");
+       }
+
+       public Map<String, String> getKnownBaseDns(boolean onlyWritable) {
+               Map<String, String> dns = new HashMap<String, String>();
+               for (UserDirectory userDirectory : userDirectories) {
+                       Boolean readOnly = userDirectory.isReadOnly();
+                       String baseDn = userDirectory.getBase();
+
+                       if (onlyWritable && readOnly)
+                               continue;
+                       if (baseDn.equalsIgnoreCase(CmsConstants.SYSTEM_ROLES_BASEDN))
+                               continue;
+                       if (baseDn.equalsIgnoreCase(CmsConstants.TOKENS_BASEDN))
+                               continue;
+                       dns.put(baseDn, DirectoryConf.propertiesAsUri(userDirectory.getProperties()).toString());
+
+               }
+               return dns;
+       }
+
+       public Set<UserDirectory> getUserDirectories() {
+               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getBase().compareTo(o2.getBase()));
+               res.addAll(userDirectories);
+               return res;
+       }
+
+       public String buildDistinguishedName(String localId, String baseDn, int type) {
+               Map<String, String> dns = getKnownBaseDns(true);
+               Dictionary<String, ?> props = DirectoryConf.uriAsProperties(dns.get(baseDn));
+               String dn = null;
+               if (Role.GROUP == type)
+                       dn = LdapAttr.cn.name() + "=" + localId + "," + DirectoryConf.groupBase.getValue(props) + "," + baseDn;
+               else if (Role.USER == type)
+                       dn = LdapAttr.uid.name() + "=" + localId + "," + DirectoryConf.userBase.getValue(props) + "," + baseDn;
+               else
+                       throw new IllegalStateException("Unknown role type. " + "Cannot deduce dn for " + localId);
+               return dn;
+       }
+
+       @Override
+       public void changeOwnPassword(char[] oldPassword, char[] newPassword) {
+               String name = CurrentUser.getUsername();
+               LdapName dn;
+               try {
+                       dn = new LdapName(name);
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Invalid user dn " + name, e);
+               }
+               User user = (User) userAdmin.getRole(dn.toString());
+               if (!user.hasCredential(null, oldPassword))
+                       throw new IllegalArgumentException("Invalid password");
+               if (Arrays.equals(newPassword, new char[0]))
+                       throw new IllegalArgumentException("New password empty");
+               try {
+                       userTransaction.begin();
+                       user.getCredentials().put(null, newPassword);
+                       userTransaction.commit();
+               } catch (Exception e) {
+                       try {
+                               userTransaction.rollback();
+                       } catch (Exception e1) {
+                               log.error("Could not roll back", e1);
+                       }
+                       if (e instanceof RuntimeException)
+                               throw (RuntimeException) e;
+                       else
+                               throw new RuntimeException("Cannot change password", e);
+               }
+       }
+
+       public void resetPassword(String username, char[] newPassword) {
+               LdapName dn;
+               try {
+                       dn = new LdapName(username);
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Invalid user dn " + username, e);
+               }
+               User user = (User) userAdmin.getRole(dn.toString());
+               if (Arrays.equals(newPassword, new char[0]))
+                       throw new IllegalArgumentException("New password empty");
+               try {
+                       userTransaction.begin();
+                       user.getCredentials().put(null, newPassword);
+                       userTransaction.commit();
+               } catch (Exception e) {
+                       try {
+                               userTransaction.rollback();
+                       } catch (Exception e1) {
+                               log.error("Could not roll back", e1);
+                       }
+                       if (e instanceof RuntimeException)
+                               throw (RuntimeException) e;
+                       else
+                               throw new RuntimeException("Cannot change password", e);
+               }
+       }
+
+       public String addSharedSecret(String email, int hours) {
+               User user = (User) userAdmin.getUser(LdapAttr.mail.name(), email);
+               try {
+                       userTransaction.begin();
+                       String uuid = UUID.randomUUID().toString();
+                       SharedSecret sharedSecret = new SharedSecret(hours, uuid);
+                       user.getCredentials().put(SharedSecret.X_SHARED_SECRET, sharedSecret.toAuthPassword());
+                       String tokenStr = sharedSecret.getAuthInfo() + '$' + sharedSecret.getAuthValue();
+                       userTransaction.commit();
+                       return tokenStr;
+               } catch (Exception e) {
+                       try {
+                               userTransaction.rollback();
+                       } catch (Exception e1) {
+                               log.error("Could not roll back", e1);
+                       }
+                       if (e instanceof RuntimeException)
+                               throw (RuntimeException) e;
+                       else
+                               throw new RuntimeException("Cannot change password", e);
+               }
+       }
+
+       @Deprecated
+       public String addSharedSecret(String username, String authInfo, String authToken) {
+               try {
+                       userTransaction.begin();
+                       User user = (User) userAdmin.getRole(username);
+                       SharedSecret sharedSecret = new SharedSecret(authInfo, authToken);
+                       user.getCredentials().put(SharedSecret.X_SHARED_SECRET, sharedSecret.toAuthPassword());
+                       String tokenStr = sharedSecret.getAuthInfo() + '$' + sharedSecret.getAuthValue();
+                       userTransaction.commit();
+                       return tokenStr;
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot add shared secret", e1);
+               }
+       }
+
+       @Override
+       public void expireAuthToken(String token) {
+               try {
+                       userTransaction.begin();
+                       String dn = cn + "=" + token + "," + CmsConstants.TOKENS_BASEDN;
+                       Group tokenGroup = (Group) userAdmin.getRole(dn);
+                       String ldapDate = NamingUtils.instantToLdapDate(ZonedDateTime.now(ZoneOffset.UTC));
+                       tokenGroup.getProperties().put(description.name(), ldapDate);
+                       userTransaction.commit();
+                       if (log.isDebugEnabled())
+                               log.debug("Token " + token + " expired.");
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot expire token", e1);
+               }
+       }
+
+       @Override
+       public void expireAuthTokens(Subject subject) {
+               Set<String> tokens = TokenUtils.tokensUsed(subject, CmsConstants.TOKENS_BASEDN);
+               for (String token : tokens)
+                       expireAuthToken(token);
+       }
+
+       @Override
+       public void addAuthToken(String userDn, String token, Integer hours, String... roles) {
+               addAuthToken(userDn, token, ZonedDateTime.now().plusHours(hours), roles);
+       }
+
+       @Override
+       public void addAuthToken(String userDn, String token, ZonedDateTime expiryDate, String... roles) {
+               try {
+                       userTransaction.begin();
+                       User user = (User) userAdmin.getRole(userDn);
+                       String tokenDn = cn + "=" + token + "," + CmsConstants.TOKENS_BASEDN;
+                       Group tokenGroup = (Group) userAdmin.createRole(tokenDn, Role.GROUP);
+                       if (roles != null)
+                               for (String role : roles) {
+                                       Role r = userAdmin.getRole(role);
+                                       if (r != null)
+                                               tokenGroup.addMember(r);
+                                       else {
+                                               if (!role.equals(CmsConstants.ROLE_USER)) {
+                                                       throw new IllegalStateException(
+                                                                       "Cannot add role " + role + " to token " + token + " for " + userDn);
+                                               }
+                                       }
+                               }
+                       tokenGroup.getProperties().put(owner.name(), user.getName());
+                       if (expiryDate != null) {
+                               String ldapDate = NamingUtils.instantToLdapDate(expiryDate);
+                               tokenGroup.getProperties().put(description.name(), ldapDate);
+                       }
+                       userTransaction.commit();
+               } catch (Exception e1) {
+                       try {
+                               if (!userTransaction.isNoTransactionStatus())
+                                       userTransaction.rollback();
+                       } catch (Exception e2) {
+                               if (log.isTraceEnabled())
+                                       log.trace("Cannot rollback transaction", e2);
+                       }
+                       throw new RuntimeException("Cannot add token", e1);
+               }
+       }
+
+       @Override
+       public UserDirectory getDirectory(Role user) {
+               String name = user.getName();
+               NavigableMap<String, UserDirectory> possible = new TreeMap<>();
+               for (UserDirectory userDirectory : userDirectories) {
+                       if (name.endsWith(userDirectory.getBase())) {
+                               possible.put(userDirectory.getBase(), userDirectory);
+                       }
+               }
+               if (possible.size() == 0)
+                       throw new IllegalStateException("No user directory found for user " + name);
+               return possible.lastEntry().getValue();
+       }
+
+//     public User createUserFromPerson(Node person) {
+//             String email = JcrUtils.get(person, LdapAttrs.mail.property());
+//             String dn = buildDefaultDN(email, Role.USER);
+//             User user;
+//             try {
+//                     userTransaction.begin();
+//                     user = (User) userAdmin.createRole(dn, Role.USER);
+//                     Dictionary<String, Object> userProperties = user.getProperties();
+//                     String name = JcrUtils.get(person, LdapAttrs.displayName.property());
+//                     userProperties.put(LdapAttrs.cn.name(), name);
+//                     userProperties.put(LdapAttrs.displayName.name(), name);
+//                     String givenName = JcrUtils.get(person, LdapAttrs.givenName.property());
+//                     String surname = JcrUtils.get(person, LdapAttrs.sn.property());
+//                     userProperties.put(LdapAttrs.givenName.name(), givenName);
+//                     userProperties.put(LdapAttrs.sn.name(), surname);
+//                     userProperties.put(LdapAttrs.mail.name(), email.toLowerCase());
+//                     userTransaction.commit();
+//             } catch (Exception e) {
+//                     try {
+//                             userTransaction.rollback();
+//                     } catch (Exception e1) {
+//                             log.error("Could not roll back", e1);
+//                     }
+//                     if (e instanceof RuntimeException)
+//                             throw (RuntimeException) e;
+//                     else
+//                             throw new RuntimeException("Cannot create user", e);
+//             }
+//             return user;
+//     }
+
+       public UserAdmin getUserAdmin() {
+               return userAdmin;
+       }
+
+//     public UserTransaction getUserTransaction() {
+//             return userTransaction;
+//     }
+
+       /* DEPENDENCY INJECTION */
+       public void setUserAdmin(UserAdmin userAdmin) {
+               this.userAdmin = userAdmin;
+
+               if (userAdmin instanceof AggregatingUserAdmin) {
+                       userDirectories = ((AggregatingUserAdmin) userAdmin).getUserDirectories();
+               } else {
+                       throw new IllegalArgumentException("Only " + AggregatingUserAdmin.class.getName() + " is supported.");
+               }
+
+//             this.serviceProperties = serviceProperties;
+       }
+
+       public void setUserTransaction(WorkTransaction userTransaction) {
+               this.userTransaction = userTransaction;
+       }
+
+//     public void addUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
+//             userDirectories.put(userDirectory, new Hashtable<>(properties));
+//     }
+//
+//     public void removeUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
+//             userDirectories.remove(userDirectory);
+//     }
+
+}
index 8358105e2982db480f79369db507b14f471b0d90..0fd0a63edb4cb47acce19bbb38f4fc07b4edd672 100644 (file)
@@ -5,7 +5,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 
 import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.CmsUserManager;
+import org.argeo.api.cms.directory.CmsUserManager;
 import org.argeo.cms.acr.CmsContentRepository;
 import org.argeo.cms.acr.directory.DirectoryContentProvider;
 import org.argeo.cms.acr.fs.FsContentProvider;
index 7165966486824fa56d842ded78c824bee0d7dc82..6e47873b35557f772ac7d702433652bdb342a3fa 100644 (file)
@@ -55,18 +55,9 @@ class KernelUtils implements KernelConstants {
                Path executionDir = Paths.get(getFrameworkProp("user.dir"));
                if (relativePath == null)
                        return executionDir;
-//             try {
                return executionDir.resolve(relativePath);
-//             } catch (IOException e) {
-//                     throw new IllegalArgumentException("Cannot get canonical file", e);
-//             }
        }
 
-//     static File getOsgiInstanceDir() {
-//             return new File(CmsActivator.getBundleContext().getProperty(OSGI_INSTANCE_AREA).substring("file:".length()))
-//                             .getAbsoluteFile();
-//     }
-
        public static Path getOsgiInstancePath(String relativePath) {
                URI uri = getOsgiInstanceUri(relativePath);
                if (uri == null) // no data area available
@@ -81,22 +72,9 @@ class KernelUtils implements KernelConstants {
 
                if (!osgiInstanceBaseUri.endsWith("/"))
                        osgiInstanceBaseUri = osgiInstanceBaseUri + "/";
-//             if (osgiInstanceBaseUri != null)
                return safeUri(osgiInstanceBaseUri + (relativePath != null ? relativePath : ""));
-//             else
-//                     return Paths.get(System.getProperty("user.dir"), (relativePath != null ? relativePath : "")).toUri();
        }
 
-//     static File getOsgiConfigurationFile(String relativePath) {
-//             try {
-//                     return new File(
-//                                     new URI(CmsActivator.getBundleContext().getProperty(OSGI_CONFIGURATION_AREA) + relativePath))
-//                                     .getCanonicalFile();
-//             } catch (Exception e) {
-//                     throw new IllegalArgumentException("Cannot get configuration file for " + relativePath, e);
-//             }
-//     }
-
        static String getFrameworkProp(String key, String def) {
                String value;
                if (CmsActivator.getBundleContext() != null)
@@ -112,32 +90,10 @@ class KernelUtils implements KernelConstants {
                return getFrameworkProp(key, null);
        }
 
-       // Security
-       // static Subject anonymousLogin() {
-       // Subject subject = new Subject();
-       // LoginContext lc;
-       // try {
-       // lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, subject);
-       // lc.login();
-       // return subject;
-       // } catch (LoginException e) {
-       // throw new CmsException("Cannot login as anonymous", e);
-       // }
-       // }
-
        static void logFrameworkProperties(CmsLog log) {
                for (Object sysProp : new TreeSet<Object>(System.getProperties().keySet())) {
                        log.debug(sysProp + "=" + getFrameworkProp(sysProp.toString()));
                }
-               // String[] keys = { Constants.FRAMEWORK_STORAGE,
-               // Constants.FRAMEWORK_OS_NAME, Constants.FRAMEWORK_OS_VERSION,
-               // Constants.FRAMEWORK_PROCESSOR, Constants.FRAMEWORK_SECURITY,
-               // Constants.FRAMEWORK_TRUST_REPOSITORIES,
-               // Constants.FRAMEWORK_WINDOWSYSTEM, Constants.FRAMEWORK_VENDOR,
-               // Constants.FRAMEWORK_VERSION, Constants.FRAMEWORK_STORAGE_CLEAN,
-               // Constants.FRAMEWORK_LANGUAGE, Constants.FRAMEWORK_UUID };
-               // for (String key : keys)
-               // log.debug(key + "=" + bc.getProperty(key));
        }
 
        static void printSystemProperties(PrintStream out) {
@@ -148,84 +104,6 @@ class KernelUtils implements KernelConstants {
                        out.println(key + "=" + display.get(key));
        }
 
-//     static Session openAdminSession(Repository repository) {
-//             return openAdminSession(repository, null);
-//     }
-//
-//     static Session openAdminSession(final Repository repository, final String workspaceName) {
-//             LoginContext loginContext = loginAsDataAdmin();
-//             return Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Session>() {
-//
-//                     @Override
-//                     public Session run() {
-//                             try {
-//                                     return repository.login(workspaceName);
-//                             } catch (RepositoryException e) {
-//                                     throw new IllegalStateException("Cannot open admin session", e);
-//                             } finally {
-//                                     try {
-//                                             loginContext.logout();
-//                                     } catch (LoginException e) {
-//                                             throw new IllegalStateException(e);
-//                                     }
-//                             }
-//                     }
-//
-//             });
-//     }
-//
-//     static LoginContext loginAsDataAdmin() {
-//             ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
-//             Thread.currentThread().setContextClassLoader(KernelUtils.class.getClassLoader());
-//             LoginContext loginContext;
-//             try {
-//                     loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN);
-//                     loginContext.login();
-//             } catch (LoginException e1) {
-//                     throw new IllegalStateException("Could not login as data admin", e1);
-//             } finally {
-//                     Thread.currentThread().setContextClassLoader(currentCl);
-//             }
-//             return loginContext;
-//     }
-
-//     static void doAsDataAdmin(Runnable action) {
-//             LoginContext loginContext = loginAsDataAdmin();
-//             Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
-//
-//                     @Override
-//                     public Void run() {
-//                             try {
-//                                     action.run();
-//                                     return null;
-//                             } finally {
-//                                     try {
-//                                             loginContext.logout();
-//                                     } catch (LoginException e) {
-//                                             throw new IllegalStateException(e);
-//                                     }
-//                             }
-//                     }
-//
-//             });
-//     }
-
-//     public static void asyncOpen(ServiceTracker<?, ?> st) {
-//             Runnable run = new Runnable() {
-//
-//                     @Override
-//                     public void run() {
-//                             st.open();
-//                     }
-//             };
-//             Activator.getInternalExecutorService().execute(run);
-////           new Thread(run, "Open service tracker " + st).start();
-//     }
-
-//     static BundleContext getBundleContext() {
-//             return Activator.getBundleContext();
-//     }
-
        static boolean asBoolean(String value) {
                if (value == null)
                        return false;
index 3443d73a67408f0f60a50c7bd2c0b6a87aa18f93..f60d3352e98c61c921b260c7be244183b91c085b 100644 (file)
@@ -17,7 +17,7 @@ import java.util.TreeSet;
 import java.util.stream.Collectors;
 
 import org.argeo.api.cms.ux.CmsTheme;
-import org.argeo.util.StreamUtils;
+import org.argeo.cms.util.StreamUtils;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/FilterRequirement.java b/org.argeo.cms/src/org/argeo/cms/osgi/FilterRequirement.java
new file mode 100644 (file)
index 0000000..5582c34
--- /dev/null
@@ -0,0 +1,42 @@
+package org.argeo.cms.osgi;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+/** Simplify filtering resources. */
+public class FilterRequirement implements Requirement {
+       private String namespace;
+       private String filter;
+
+       public FilterRequirement(String namespace, String filter) {
+               this.namespace = namespace;
+               this.filter = filter;
+       }
+
+       @Override
+       public Resource getResource() {
+               return null;
+       }
+
+       @Override
+       public String getNamespace() {
+               return namespace;
+       }
+
+       @Override
+       public Map<String, String> getDirectives() {
+               Map<String, String> directives = new HashMap<>();
+               directives.put(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter);
+               return directives;
+       }
+
+       @Override
+       public Map<String, Object> getAttributes() {
+               return new HashMap<>();
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AggregatingAuthorization.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AggregatingAuthorization.java
new file mode 100644 (file)
index 0000000..72c4336
--- /dev/null
@@ -0,0 +1,78 @@
+package org.argeo.cms.osgi.useradmin;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.argeo.api.cms.directory.CmsAuthorization;
+import org.osgi.service.useradmin.Authorization;
+
+/** An {@link Authorization} which combines roles form various auth sources. */
+class AggregatingAuthorization implements CmsAuthorization {
+       private final String name;
+       private final String displayName;
+       private final Set<String> systemRoles;
+       private final Set<String> roles;
+
+       public AggregatingAuthorization(String name, String displayName, Set<String> systemRoles, String[] roles) {
+               this.name = new X500Principal(name).getName();
+               this.displayName = displayName;
+               this.systemRoles = Collections.unmodifiableSet(new HashSet<>(systemRoles));
+               Set<String> temp = new HashSet<>();
+               for (String role : roles) {
+                       if (!temp.contains(role))
+                               temp.add(role);
+               }
+               this.roles = Collections.unmodifiableSet(temp);
+       }
+
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       @Override
+       public boolean hasRole(String name) {
+               if (systemRoles.contains(name))
+                       return true;
+               if (roles.contains(name))
+                       return true;
+               return false;
+       }
+
+       @Override
+       public String[] getRoles() {
+               int size = systemRoles.size() + roles.size();
+               List<String> res = new ArrayList<String>(size);
+               res.addAll(systemRoles);
+               res.addAll(roles);
+               return res.toArray(new String[size]);
+       }
+
+       @Override
+       public int hashCode() {
+               if (name == null)
+                       return super.hashCode();
+               return name.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof Authorization))
+                       return false;
+               Authorization that = (Authorization) obj;
+               if (name == null)
+                       return that.getName() == null;
+               return name.equals(that.getName());
+       }
+
+       @Override
+       public String toString() {
+               return displayName;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AggregatingUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AggregatingUserAdmin.java
new file mode 100644 (file)
index 0000000..8ebb98e
--- /dev/null
@@ -0,0 +1,330 @@
+package org.argeo.cms.osgi.useradmin;
+
+import static org.argeo.cms.osgi.useradmin.DirectoryUserAdmin.toLdapName;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.cms.directory.CmsUser;
+import org.argeo.api.cms.directory.UserDirectory;
+import org.argeo.cms.runtime.DirectoryConf;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Group;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Aggregates multiple {@link UserDirectory} and integrates them with system
+ * roles.
+ */
+public class AggregatingUserAdmin implements UserAdmin {
+       private final LdapName systemRolesBaseDn;
+       private final LdapName tokensBaseDn;
+
+       // DAOs
+       private DirectoryUserAdmin systemRoles = null;
+       private DirectoryUserAdmin tokens = null;
+       private Map<LdapName, DirectoryUserAdmin> businessRoles = new HashMap<LdapName, DirectoryUserAdmin>();
+
+       // TODO rather use an empty constructor and an init method
+       public AggregatingUserAdmin(String systemRolesBaseDn, String tokensBaseDn) {
+               try {
+                       this.systemRolesBaseDn = new LdapName(systemRolesBaseDn);
+                       if (tokensBaseDn != null)
+                               this.tokensBaseDn = new LdapName(tokensBaseDn);
+                       else
+                               this.tokensBaseDn = null;
+               } catch (InvalidNameException e) {
+                       throw new IllegalStateException("Cannot initialize " + AggregatingUserAdmin.class, e);
+               }
+       }
+
+       @Override
+       public Role createRole(String name, int type) {
+               return findUserAdmin(name).createRole(name, type);
+       }
+
+       @Override
+       public boolean removeRole(String name) {
+               boolean actuallyDeleted = findUserAdmin(name).removeRole(name);
+               systemRoles.removeRole(name);
+               return actuallyDeleted;
+       }
+
+       @Override
+       public Role getRole(String name) {
+               return findUserAdmin(name).getRole(name);
+       }
+
+       @Override
+       public Role[] getRoles(String filter) throws InvalidSyntaxException {
+               List<Role> res = new ArrayList<Role>();
+               for (UserAdmin userAdmin : businessRoles.values()) {
+                       res.addAll(Arrays.asList(userAdmin.getRoles(filter)));
+               }
+               res.addAll(Arrays.asList(systemRoles.getRoles(filter)));
+               return res.toArray(new Role[res.size()]);
+       }
+
+       @Override
+       public User getUser(String key, String value) {
+               List<User> res = new ArrayList<User>();
+               for (UserAdmin userAdmin : businessRoles.values()) {
+                       User u = userAdmin.getUser(key, value);
+                       if (u != null)
+                               res.add(u);
+               }
+               // Note: node roles cannot contain users, so it is not searched
+               return res.size() == 1 ? res.get(0) : null;
+       }
+
+       /** Builds an authorisation by scanning all referentials. */
+       @Override
+       public Authorization getAuthorization(User user) {
+               if (user == null) {// anonymous
+                       return systemRoles.getAuthorization(null);
+               }
+               DirectoryUserAdmin userReferentialOfThisUser = findUserAdmin(user.getName());
+               Authorization rawAuthorization = userReferentialOfThisUser.getAuthorization(user);
+               User retrievedUser = (User) userReferentialOfThisUser.getRole(user.getName());
+               String usernameToUse;
+               String displayNameToUse;
+               if (user instanceof Group) {
+                       // TODO check whether this is still working
+                       String ownerDn = TokenUtils.userDn((Group) user);
+                       if (ownerDn != null) {// tokens
+                               UserAdmin ownerUserAdmin = findUserAdmin(ownerDn);
+                               User ownerUser = (User) ownerUserAdmin.getRole(ownerDn);
+                               usernameToUse = ownerDn;
+                               displayNameToUse = LdifAuthorization.extractDisplayName(ownerUser);
+                       } else {
+                               usernameToUse = rawAuthorization.getName();
+                               displayNameToUse = rawAuthorization.toString();
+                       }
+               } else {// regular users
+                       usernameToUse = rawAuthorization.getName();
+                       displayNameToUse = rawAuthorization.toString();
+               }
+
+               // gather roles from other referentials
+               List<String> rawRoles = Arrays.asList(rawAuthorization.getRoles());
+               List<String> allRoles = new ArrayList<>(rawRoles);
+               for (LdapName otherBaseDn : businessRoles.keySet()) {
+                       if (otherBaseDn.equals(userReferentialOfThisUser.getBaseDn()))
+                               continue;
+                       DirectoryUserAdmin otherUserAdmin = userAdminToUse(user, businessRoles.get(otherBaseDn));
+                       if (otherUserAdmin == null)
+                               continue;
+                       for (String roleStr : rawRoles) {
+                               User role = (User) findUserAdmin(roleStr).getRole(roleStr);
+                               Authorization auth = otherUserAdmin.getAuthorization(role);
+                               allRoles.addAll(Arrays.asList(auth.getRoles()));
+                       }
+
+               }
+
+               // integrate system roles
+               final DirectoryUserAdmin userAdminToUse = userAdminToUse(retrievedUser, userReferentialOfThisUser);
+               Objects.requireNonNull(userAdminToUse);
+
+               try {
+                       Set<String> sysRoles = new HashSet<String>();
+                       for (String role : rawAuthorization.getRoles()) {
+                               User userOrGroup = (User) userAdminToUse.getRole(role);
+                               Authorization auth = systemRoles.getAuthorization(userOrGroup);
+                               systemRoles: for (String systemRole : auth.getRoles()) {
+                                       if (role.equals(systemRole))
+                                               continue systemRoles;
+                                       sysRoles.add(systemRole);
+                               }
+//                     sysRoles.addAll(Arrays.asList(auth.getRoles()));
+                       }
+                       addAbstractSystemRoles(rawAuthorization, sysRoles);
+                       Authorization authorization = new AggregatingAuthorization(usernameToUse, displayNameToUse, sysRoles,
+                                       allRoles.toArray(new String[allRoles.size()]));
+                       return authorization;
+               } finally {
+                       if (userAdminToUse != null && userAdminToUse.isScoped()) {
+                               userAdminToUse.destroy();
+                       }
+               }
+       }
+
+       /** Decide whether to scope or not */
+       private DirectoryUserAdmin userAdminToUse(User user, DirectoryUserAdmin userAdmin) {
+               if (userAdmin.isAuthenticated())
+                       return userAdmin;
+               if (user instanceof CmsUser) {
+                       return userAdmin;
+               } else if (user instanceof AuthenticatingUser) {
+                       return userAdmin.scope(user).orElse(null);
+               } else {
+                       throw new IllegalArgumentException("Unsupported user type " + user.getClass());
+               }
+
+       }
+
+       /**
+        * Enrich with application-specific roles which are strictly programmatic, such
+        * as anonymous/user semantics.
+        */
+       protected void addAbstractSystemRoles(Authorization rawAuthorization, Set<String> sysRoles) {
+
+       }
+
+       //
+       // USER ADMIN AGGREGATOR
+       //
+       protected void addUserDirectory(UserDirectory ud) {
+               if (!(ud instanceof DirectoryUserAdmin))
+                       throw new IllegalArgumentException("Only " + DirectoryUserAdmin.class.getName() + " is supported");
+               DirectoryUserAdmin userDirectory = (DirectoryUserAdmin) ud;
+               String basePath = userDirectory.getBase();
+               if (isSystemRolesBaseDn(basePath)) {
+                       this.systemRoles = userDirectory;
+                       systemRoles.setExternalRoles(this);
+               } else if (isTokensBaseDn(basePath)) {
+                       this.tokens = userDirectory;
+                       tokens.setExternalRoles(this);
+               } else {
+                       LdapName baseDn = toLdapName(basePath);
+                       if (businessRoles.containsKey(baseDn))
+                               throw new IllegalStateException("There is already a user admin for " + baseDn);
+                       businessRoles.put(baseDn, userDirectory);
+               }
+               userDirectory.init();
+               postAdd(userDirectory);
+       }
+
+       /** Called after a new user directory has been added */
+       protected void postAdd(UserDirectory userDirectory) {
+       }
+
+       private DirectoryUserAdmin findUserAdmin(String name) {
+               try {
+                       return findUserAdmin(new LdapName(name));
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Badly formatted name " + name, e);
+               }
+       }
+
+       private DirectoryUserAdmin findUserAdmin(LdapName name) {
+               if (name.startsWith(systemRolesBaseDn))
+                       return systemRoles;
+               if (tokensBaseDn != null && name.startsWith(tokensBaseDn))
+                       return tokens;
+               List<DirectoryUserAdmin> res = new ArrayList<>(1);
+               userDirectories: for (LdapName baseDn : businessRoles.keySet()) {
+                       DirectoryUserAdmin userDirectory = businessRoles.get(baseDn);
+                       if (name.startsWith(baseDn)) {
+                               if (userDirectory.isDisabled())
+                                       continue userDirectories;
+//                             if (res.isEmpty()) {
+                               res.add(userDirectory);
+//                             } else {
+//                                     for (AbstractUserDirectory ud : res) {
+//                                             LdapName bd = ud.getBaseDn();
+//                                             if (userDirectory.getBaseDn().startsWith(bd)) {
+//                                                     // child user directory
+//                                             }
+//                                     }
+//                             }
+                       }
+               }
+               if (res.size() == 0)
+                       throw new IllegalStateException("Cannot find user admin for " + name);
+               if (res.size() > 1)
+                       throw new IllegalStateException("Multiple user admin found for " + name);
+               return res.get(0);
+       }
+
+       protected boolean isSystemRolesBaseDn(String basePath) {
+               return toLdapName(basePath).equals(systemRolesBaseDn);
+       }
+
+       protected boolean isTokensBaseDn(String basePath) {
+               return tokensBaseDn != null && toLdapName(basePath).equals(tokensBaseDn);
+       }
+
+//     protected Dictionary<String, Object> currentState() {
+//             Dictionary<String, Object> res = new Hashtable<String, Object>();
+//             // res.put(NodeConstants.CN, NodeConstants.DEFAULT);
+//             for (LdapName name : businessRoles.keySet()) {
+//                     AbstractUserDirectory userDirectory = businessRoles.get(name);
+//                     String uri = UserAdminConf.propertiesAsUri(userDirectory.getProperties()).toString();
+//                     res.put(uri, "");
+//             }
+//             return res;
+//     }
+
+       public void start() {
+               if (systemRoles == null) {
+                       // TODO do we really need separate system roles?
+                       Hashtable<String, Object> properties = new Hashtable<>();
+                       properties.put(DirectoryConf.baseDn.name(), "ou=roles,ou=system");
+                       systemRoles = new DirectoryUserAdmin(properties);
+               }
+       }
+
+       public void stop() {
+               for (LdapName name : businessRoles.keySet()) {
+                       DirectoryUserAdmin userDirectory = businessRoles.get(name);
+                       destroy(userDirectory);
+               }
+               businessRoles.clear();
+               businessRoles = null;
+               destroy(systemRoles);
+               systemRoles = null;
+       }
+
+       private void destroy(DirectoryUserAdmin userDirectory) {
+               preDestroy(userDirectory);
+               userDirectory.destroy();
+       }
+
+//     protected void removeUserDirectory(UserDirectory userDirectory) {
+//             LdapName baseDn = toLdapName(userDirectory.getContext());
+//             businessRoles.remove(baseDn);
+//             if (userDirectory instanceof DirectoryUserAdmin)
+//                     destroy((DirectoryUserAdmin) userDirectory);
+//     }
+
+       @Deprecated
+       protected void removeUserDirectory(String basePath) {
+               if (isSystemRolesBaseDn(basePath))
+                       throw new IllegalArgumentException("System roles cannot be removed ");
+               LdapName baseDn = toLdapName(basePath);
+               if (!businessRoles.containsKey(baseDn))
+                       throw new IllegalStateException("No user directory registered for " + baseDn);
+               DirectoryUserAdmin userDirectory = businessRoles.remove(baseDn);
+               destroy(userDirectory);
+       }
+
+       /**
+        * Called before each user directory is destroyed, so that additional actions
+        * can be performed.
+        */
+       protected void preDestroy(UserDirectory userDirectory) {
+       }
+
+       public Set<UserDirectory> getUserDirectories() {
+               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getBase().compareTo(o2.getBase()));
+               res.addAll(businessRoles.values());
+               res.add(systemRoles);
+               return res;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AuthenticatingUser.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/AuthenticatingUser.java
new file mode 100644 (file)
index 0000000..b87dc9b
--- /dev/null
@@ -0,0 +1,83 @@
+package org.argeo.cms.osgi.useradmin;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.cms.directory.DirectoryDigestUtils;
+import org.osgi.service.useradmin.User;
+
+/**
+ * A special user type used during authentication in order to provide the
+ * credentials required for scoping the user admin.
+ */
+public class AuthenticatingUser implements User {
+       /** From com.sun.security.auth.module.*LoginModule */
+       public final static String SHARED_STATE_NAME = "javax.security.auth.login.name";
+       /** From com.sun.security.auth.module.*LoginModule */
+       public final static String SHARED_STATE_PWD = "javax.security.auth.login.password";
+
+       private final String name;
+       private final Dictionary<String, Object> credentials;
+
+       public AuthenticatingUser(LdapName name) {
+               if (name == null)
+                       throw new NullPointerException("Provided name cannot be null.");
+               this.name = name.toString();
+               this.credentials = new Hashtable<>();
+       }
+
+       public AuthenticatingUser(String name, Dictionary<String, Object> credentials) {
+               this.name = name;
+               this.credentials = credentials;
+       }
+
+       public AuthenticatingUser(String name, char[] password) {
+               if (name == null)
+                       throw new NullPointerException("Provided name cannot be null.");
+               this.name = name;
+               credentials = new Hashtable<>();
+               credentials.put(SHARED_STATE_NAME, name);
+               byte[] pwd = DirectoryDigestUtils.charsToBytes(password);
+               credentials.put(SHARED_STATE_PWD, pwd);
+       }
+
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       @Override
+       public int getType() {
+               return User.USER;
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       @Override
+       public Dictionary getProperties() {
+               throw new UnsupportedOperationException();
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       @Override
+       public Dictionary getCredentials() {
+               return credentials;
+       }
+
+       @Override
+       public boolean hasCredential(String key, Object value) {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public int hashCode() {
+               return name.hashCode();
+       }
+
+       @Override
+       public String toString() {
+               return "Authenticating user " + name;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/DirectoryUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/DirectoryUserAdmin.java
new file mode 100644 (file)
index 0000000..03f17e6
--- /dev/null
@@ -0,0 +1,402 @@
+package org.argeo.cms.osgi.useradmin;
+
+import static org.argeo.api.acr.ldap.LdapAttr.objectClass;
+import static org.argeo.api.acr.ldap.LdapObj.extensibleObject;
+import static org.argeo.api.acr.ldap.LdapObj.inetOrgPerson;
+import static org.argeo.api.acr.ldap.LdapObj.organizationalPerson;
+import static org.argeo.api.acr.ldap.LdapObj.person;
+import static org.argeo.api.acr.ldap.LdapObj.top;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosTicket;
+
+import org.argeo.api.cms.directory.DirectoryDigestUtils;
+import org.argeo.api.cms.directory.CmsUser;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.api.cms.directory.UserDirectory;
+import org.argeo.cms.directory.ldap.AbstractLdapDirectory;
+import org.argeo.cms.directory.ldap.LdapDao;
+import org.argeo.cms.directory.ldap.LdapEntry;
+import org.argeo.cms.directory.ldap.LdapEntryWorkingCopy;
+import org.argeo.cms.directory.ldap.LdapNameUtils;
+import org.argeo.cms.directory.ldap.LdifDao;
+import org.argeo.cms.runtime.DirectoryConf;
+import org.argeo.cms.util.CurrentSubject;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/** Base class for a {@link UserDirectory}. */
+public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdmin, UserDirectory {
+
+       private UserAdmin externalRoles;
+
+       // Transaction
+       public DirectoryUserAdmin(URI uriArg, Dictionary<String, ?> props) {
+               this(uriArg, props, false);
+       }
+
+       public DirectoryUserAdmin(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
+               super(uriArg, props, scoped);
+       }
+
+       public DirectoryUserAdmin(Dictionary<String, ?> props) {
+               this(null, props);
+       }
+
+       /*
+        * ABSTRACT METHODS
+        */
+
+       protected Optional<DirectoryUserAdmin> scope(User user) {
+               if (getDirectoryDao() instanceof LdapDao) {
+                       return scopeLdap(user);
+               } else if (getDirectoryDao() instanceof LdifDao) {
+                       return scopeLdif(user);
+               } else {
+                       throw new IllegalStateException("Unsupported DAO " + getDirectoryDao().getClass());
+               }
+       }
+
+       protected Optional<DirectoryUserAdmin> scopeLdap(User user) {
+               Dictionary<String, Object> credentials = user.getCredentials();
+               String username = (String) credentials.get(SHARED_STATE_USERNAME);
+               if (username == null)
+                       username = user.getName();
+               Dictionary<String, Object> properties = cloneConfigProperties();
+               properties.put(Context.SECURITY_PRINCIPAL, username.toString());
+               Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
+               byte[] pwd = (byte[]) pwdCred;
+               if (pwd != null) {
+                       char[] password = DirectoryDigestUtils.bytesToChars(pwd);
+                       properties.put(Context.SECURITY_CREDENTIALS, new String(password));
+               } else {
+                       properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
+               }
+               DirectoryUserAdmin scopedDirectory = new DirectoryUserAdmin(null, properties, true);
+               scopedDirectory.init();
+               // check connection
+               if (!scopedDirectory.getDirectoryDao().checkConnection())
+                       return Optional.empty();
+               return Optional.of(scopedDirectory);
+       }
+
+       protected Optional<DirectoryUserAdmin> scopeLdif(User user) {
+               Dictionary<String, Object> credentials = user.getCredentials();
+               String username = (String) credentials.get(SHARED_STATE_USERNAME);
+               if (username == null)
+                       username = user.getName();
+               Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
+               byte[] pwd = (byte[]) pwdCred;
+               if (pwd != null) {
+                       char[] password = DirectoryDigestUtils.bytesToChars(pwd);
+                       User directoryUser = (User) getRole(username);
+                       if (!directoryUser.hasCredential(null, password))
+                               throw new IllegalStateException("Invalid credentials");
+               } else {
+                       throw new IllegalStateException("Password is required");
+               }
+               Dictionary<String, Object> properties = cloneConfigProperties();
+               properties.put(DirectoryConf.readOnly.name(), "true");
+               DirectoryUserAdmin scopedUserAdmin = new DirectoryUserAdmin(null, properties, true);
+               // FIXME do it better
+               ((LdifDao) getDirectoryDao()).scope((LdifDao) scopedUserAdmin.getDirectoryDao());
+               // no need to check authentication
+               scopedUserAdmin.init();
+               return Optional.of(scopedUserAdmin);
+       }
+
+       @Override
+       public String getRolePath(Role role) {
+               return nameToRelativePath(LdapNameUtils.toLdapName(role.getName()));
+       }
+
+       @Override
+       public String getRoleSimpleName(Role role) {
+               LdapName dn = LdapNameUtils.toLdapName(role.getName());
+               String name = LdapNameUtils.getLastRdnValue(dn);
+               return name;
+       }
+
+       @Override
+       public Role getRoleByPath(String path) {
+               LdapEntry entry = doGetRole(pathToName(path));
+               if (!(entry instanceof Role)) {
+                       return null;
+//                     throw new IllegalStateException("Path must be a UserAdmin Role.");
+               } else {
+                       return (Role) entry;
+               }
+       }
+
+       protected List<Role> getAllRoles(CmsUser user) {
+               List<Role> allRoles = new ArrayList<Role>();
+               if (user != null) {
+                       collectRoles((LdapEntry) user, allRoles);
+                       allRoles.add(user);
+               } else
+                       collectAnonymousRoles(allRoles);
+               return allRoles;
+       }
+
+       private void collectRoles(LdapEntry user, List<Role> allRoles) {
+               List<LdapEntry> allEntries = new ArrayList<>();
+               LdapEntry entry = user;
+               collectGroups(entry, allEntries);
+               for (LdapEntry e : allEntries) {
+                       if (e instanceof Role)
+                               allRoles.add((Role) e);
+               }
+       }
+
+       private void collectAnonymousRoles(List<Role> allRoles) {
+               // TODO gather anonymous roles
+       }
+
+       // USER ADMIN
+       @Override
+       public Role getRole(String name) {
+               return (Role) doGetRole(toLdapName(name));
+       }
+
+       @Override
+       public Role[] getRoles(String filter) throws InvalidSyntaxException {
+               List<? extends Role> res = getRoles(getBaseDn(), filter, true);
+               return res.toArray(new Role[res.size()]);
+       }
+
+       List<CmsUser> getRoles(LdapName searchBase, String filter, boolean deep) throws InvalidSyntaxException {
+               LdapEntryWorkingCopy wc = getWorkingCopy();
+//             Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
+               List<LdapEntry> searchRes = getDirectoryDao().doGetEntries(searchBase, filter, deep);
+               List<CmsUser> res = new ArrayList<>();
+               for (LdapEntry entry : searchRes)
+                       res.add((CmsUser) entry);
+               if (wc != null) {
+                       for (Iterator<CmsUser> it = res.iterator(); it.hasNext();) {
+                               CmsUser user = (CmsUser) it.next();
+                               LdapName dn = LdapNameUtils.toLdapName(user.getName());
+                               if (wc.getDeletedData().containsKey(dn))
+                                       it.remove();
+                       }
+                       Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
+                       for (LdapEntry ldapEntry : wc.getNewData().values()) {
+                               CmsUser user = (CmsUser) ldapEntry;
+                               if (f == null || f.match(user.getProperties()))
+                                       res.add(user);
+                       }
+                       // no need to check modified users,
+                       // since doGetRoles was already based on the modified attributes
+               }
+               return res;
+       }
+
+       @Override
+       public User getUser(String key, String value) {
+               // TODO check value null or empty
+               List<CmsUser> collectedUsers = new ArrayList<CmsUser>();
+               if (key != null) {
+                       doGetUser(key, value, collectedUsers);
+               } else {
+                       throw new IllegalArgumentException("Key cannot be null");
+               }
+
+               if (collectedUsers.size() == 1) {
+                       return collectedUsers.get(0);
+               } else if (collectedUsers.size() > 1) {
+                       // log.warn(collectedUsers.size() + " users for " + (key != null ? key + "=" :
+                       // "") + value);
+               }
+               return null;
+       }
+
+       protected void doGetUser(String key, String value, List<CmsUser> collectedUsers) {
+               String f = "(" + key + "=" + value + ")";
+               List<LdapEntry> users = getDirectoryDao().doGetEntries(getBaseDn(), f, true);
+               for (LdapEntry entry : users)
+                       collectedUsers.add((CmsUser) entry);
+       }
+
+       @Override
+       public Authorization getAuthorization(User user) {
+               if (user == null) {// anonymous
+                       return new LdifAuthorization(user, getAllRoles(null));
+               }
+               LdapName userName = toLdapName(user.getName());
+               if (isExternal(userName) && user instanceof LdapEntry) {
+                       List<Role> allRoles = new ArrayList<Role>();
+                       collectRoles((LdapEntry) user, allRoles);
+                       return new LdifAuthorization(user, allRoles);
+               } else {
+
+                       Subject currentSubject = CurrentSubject.current();
+                       if (currentSubject != null //
+                                       && getRealm().isPresent() //
+                                       && !currentSubject.getPrivateCredentials(Authorization.class).isEmpty() //
+                                       && !currentSubject.getPrivateCredentials(KerberosTicket.class).isEmpty()) //
+                       {
+                               // TODO not only Kerberos but also bind scope with kept password ?
+                               Authorization auth = currentSubject.getPrivateCredentials(Authorization.class).iterator().next();
+                               // bind with authenticating user
+                               DirectoryUserAdmin scopedUserAdmin = CurrentSubject.callAs(currentSubject, () -> {
+                                       return scope(new AuthenticatingUser(auth.getName(), new Hashtable<>())).orElseThrow();
+                               });
+                               return getAuthorizationFromScoped(scopedUserAdmin, user);
+                       }
+
+                       if (user instanceof CmsUser) {
+                               return new LdifAuthorization(user, getAllRoles((CmsUser) user));
+                       } else {
+                               // bind with authenticating user
+                               DirectoryUserAdmin scopedUserAdmin = scope(user).orElseThrow();
+                               return getAuthorizationFromScoped(scopedUserAdmin, user);
+                       }
+               }
+       }
+
+       private Authorization getAuthorizationFromScoped(DirectoryUserAdmin scopedUserAdmin, User user) {
+               try {
+                       CmsUser directoryUser = (CmsUser) scopedUserAdmin.getRole(user.getName());
+                       if (directoryUser == null)
+                               throw new IllegalStateException("No scoped user found for " + user);
+                       LdifAuthorization authorization = new LdifAuthorization(directoryUser,
+                                       scopedUserAdmin.getAllRoles(directoryUser));
+                       return authorization;
+               } finally {
+                       scopedUserAdmin.destroy();
+               }
+       }
+
+       @Override
+       public Role createRole(String name, int type) {
+               checkEdit();
+               LdapEntryWorkingCopy wc = getWorkingCopy();
+               LdapName dn = toLdapName(name);
+               if ((getDirectoryDao().entryExists(dn) && !wc.getDeletedData().containsKey(dn))
+                               || wc.getNewData().containsKey(dn))
+                       throw new IllegalArgumentException("Already a role " + name);
+               BasicAttributes attrs = new BasicAttributes(true);
+               // attrs.put(LdifName.dn.name(), dn.toString());
+               Rdn nameRdn = dn.getRdn(dn.size() - 1);
+               // TODO deal with multiple attr RDN
+               attrs.put(nameRdn.getType(), nameRdn.getValue());
+               if (wc.getDeletedData().containsKey(dn)) {
+                       wc.getDeletedData().remove(dn);
+                       wc.getModifiedData().put(dn, attrs);
+                       return getRole(name);
+               } else {
+                       wc.getModifiedData().put(dn, attrs);
+                       LdapEntry newRole = doCreateRole(dn, type, attrs);
+                       wc.getNewData().put(dn, newRole);
+                       return (Role) newRole;
+               }
+       }
+
+       private LdapEntry doCreateRole(LdapName dn, int type, Attributes attrs) {
+               LdapEntry newRole;
+               BasicAttribute objClass = new BasicAttribute(objectClass.name());
+               if (type == Role.USER) {
+                       String userObjClass = getUserObjectClass();
+                       objClass.add(userObjClass);
+                       if (inetOrgPerson.name().equals(userObjClass)) {
+                               objClass.add(organizationalPerson.name());
+                               objClass.add(person.name());
+                       } else if (organizationalPerson.name().equals(userObjClass)) {
+                               objClass.add(person.name());
+                       }
+                       objClass.add(top.name());
+                       objClass.add(extensibleObject.name());
+                       attrs.put(objClass);
+                       newRole = newUser(dn);
+               } else if (type == Role.GROUP) {
+                       String groupObjClass = getGroupObjectClass();
+                       objClass.add(groupObjClass);
+                       // objClass.add(LdifName.extensibleObject.name());
+                       objClass.add(top.name());
+                       attrs.put(objClass);
+                       newRole = newGroup(dn);
+               } else
+                       throw new IllegalArgumentException("Unsupported type " + type);
+               return newRole;
+       }
+
+       @Override
+       public boolean removeRole(String name) {
+               return removeEntry(LdapNameUtils.toLdapName(name));
+       }
+
+       /*
+        * HIERARCHY
+        */
+       @Override
+       public HierarchyUnit getHierarchyUnit(Role role) {
+               LdapName dn = LdapNameUtils.toLdapName(role.getName());
+               LdapName huDn = LdapNameUtils.getParent(dn);
+               HierarchyUnit hierarchyUnit = getDirectoryDao().doGetHierarchyUnit(huDn);
+               if (hierarchyUnit == null)
+                       throw new IllegalStateException("No hierarchy unit found for " + role);
+               return hierarchyUnit;
+       }
+
+       @Override
+       public Iterable<? extends Role> getHierarchyUnitRoles(HierarchyUnit hierarchyUnit, String filter, boolean deep) {
+               LdapName dn = LdapNameUtils.toLdapName(hierarchyUnit.getBase());
+               try {
+                       return getRoles(dn, filter, deep);
+               } catch (InvalidSyntaxException e) {
+                       throw new IllegalArgumentException("Cannot filter " + filter + " " + dn, e);
+               }
+       }
+
+       /*
+        * ROLES CREATION
+        */
+       protected LdapEntry newUser(LdapName name) {
+               // TODO support devices, applications, etc.
+               return new LdifUser(this, name);
+       }
+
+       protected LdapEntry newGroup(LdapName name) {
+               return new LdifGroup(this, name);
+
+       }
+
+       // GETTERS
+       protected UserAdmin getExternalRoles() {
+               return externalRoles;
+       }
+
+       public void setExternalRoles(UserAdmin externalRoles) {
+               this.externalRoles = externalRoles;
+       }
+
+       /*
+        * STATIC UTILITIES
+        */
+       static LdapName toLdapName(String name) {
+               try {
+                       return new LdapName(name);
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException(name + " is not an LDAP name", e);
+               }
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifAuthorization.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifAuthorization.java
new file mode 100644 (file)
index 0000000..a54050b
--- /dev/null
@@ -0,0 +1,85 @@
+package org.argeo.cms.osgi.useradmin;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+
+/** Basic authorization. */
+class LdifAuthorization implements Authorization {
+       private final String name;
+       private final String displayName;
+       private final List<String> allRoles;
+
+       public LdifAuthorization(User user, List<Role> allRoles) {
+               if (user == null) {
+                       this.name = null;
+                       this.displayName = "anonymous";
+               } else {
+                       this.name = user.getName();
+                       this.displayName = extractDisplayName(user);
+               }
+               // roles
+               String[] roles = new String[allRoles.size()];
+               for (int i = 0; i < allRoles.size(); i++) {
+                       roles[i] = allRoles.get(i).getName();
+               }
+               this.allRoles = Collections.unmodifiableList(Arrays.asList(roles));
+       }
+
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       @Override
+       public boolean hasRole(String name) {
+               return allRoles.contains(name);
+       }
+
+       @Override
+       public String[] getRoles() {
+               return allRoles.toArray(new String[allRoles.size()]);
+       }
+
+       @Override
+       public int hashCode() {
+               if (name == null)
+                       return super.hashCode();
+               return name.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (!(obj instanceof Authorization))
+                       return false;
+               Authorization that = (Authorization) obj;
+               if (name == null)
+                       return that.getName() == null;
+               return name.equals(that.getName());
+       }
+
+       @Override
+       public String toString() {
+               return displayName;
+       }
+
+       final static String extractDisplayName(User user) {
+               Dictionary<String, Object> props = user.getProperties();
+               Object displayName = props.get(LdapAttr.displayName.name());
+               if (displayName == null)
+                       displayName = props.get(LdapAttr.cn.name());
+               if (displayName == null)
+                       displayName = props.get(LdapAttr.uid.name());
+               if (displayName == null)
+                       displayName = user.getName();
+               if (displayName == null)
+                       throw new IllegalStateException("Cannot set display name for " + user);
+               return displayName.toString();
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifGroup.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifGroup.java
new file mode 100644 (file)
index 0000000..99aca1f
--- /dev/null
@@ -0,0 +1,128 @@
+package org.argeo.cms.osgi.useradmin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.naming.InvalidNameException;
+import javax.naming.directory.Attribute;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.cms.directory.CmsGroup;
+import org.argeo.cms.directory.ldap.AbstractLdapDirectory;
+import org.osgi.service.useradmin.Role;
+
+/** Directory group implementation */
+class LdifGroup extends LdifUser implements CmsGroup {
+       private final String memberAttributeId;
+
+       LdifGroup(AbstractLdapDirectory userAdmin, LdapName dn) {
+               super(userAdmin, dn);
+               memberAttributeId = userAdmin.getMemberAttributeId();
+       }
+
+       @Override
+       public boolean addMember(Role role) {
+               try {
+                       Role foundRole = findRole(new LdapName(role.getName()));
+                       if (foundRole == null)
+                               throw new UnsupportedOperationException(
+                                               "Adding role " + role.getName() + " is unsupported within this context.");
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Role name" + role.getName() + " is badly formatted");
+               }
+
+               getUserAdmin().checkEdit();
+               if (!isEditing())
+                       startEditing();
+
+               Attribute member = getAttributes().get(memberAttributeId);
+               if (member != null) {
+                       if (member.contains(role.getName()))
+                               return false;
+                       else
+                               member.add(role.getName());
+               } else
+                       getAttributes().put(memberAttributeId, role.getName());
+               return true;
+       }
+
+       @Override
+       public boolean addRequiredMember(Role role) {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public boolean removeMember(Role role) {
+               getUserAdmin().checkEdit();
+               if (!isEditing())
+                       startEditing();
+
+               Attribute member = getAttributes().get(memberAttributeId);
+               if (member != null) {
+                       if (!member.contains(role.getName()))
+                               return false;
+                       member.remove(role.getName());
+                       return true;
+               } else
+                       return false;
+       }
+
+       @Override
+       public Role[] getMembers() {
+               List<Role> directMembers = new ArrayList<Role>();
+               for (LdapName ldapName : getReferences(memberAttributeId)) {
+                       Role role = findRole(ldapName);
+                       if (role == null) {
+                               throw new IllegalStateException("Role " + ldapName + " not found.");
+                       }
+                       directMembers.add(role);
+               }
+               return directMembers.toArray(new Role[directMembers.size()]);
+       }
+
+       /**
+        * Whether a role with this name can be found from this context.
+        * 
+        * @return The related {@link Role} or <code>null</code>.
+        */
+       protected Role findRole(LdapName ldapName) {
+               Role role = getUserAdmin().getRole(ldapName.toString());
+               if (role == null) {
+                       if (getUserAdmin().getExternalRoles() != null)
+                               role = getUserAdmin().getExternalRoles().getRole(ldapName.toString());
+               }
+               return role;
+       }
+
+//     @Override
+//     public List<LdapName> getMemberNames() {
+//             Attribute memberAttribute = getAttributes().get(memberAttributeId);
+//             if (memberAttribute == null)
+//                     return new ArrayList<LdapName>();
+//             try {
+//                     List<LdapName> roles = new ArrayList<LdapName>();
+//                     NamingEnumeration<?> values = memberAttribute.getAll();
+//                     while (values.hasMore()) {
+//                             LdapName dn = new LdapName(values.next().toString());
+//                             roles.add(dn);
+//                     }
+//                     return roles;
+//             } catch (NamingException e) {
+//                     throw new IllegalStateException("Cannot get members", e);
+//             }
+//     }
+
+       @Override
+       public Role[] getRequiredMembers() {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public int getType() {
+               return GROUP;
+       }
+
+       protected DirectoryUserAdmin getUserAdmin() {
+               return (DirectoryUserAdmin) getDirectory();
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifUser.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/LdifUser.java
new file mode 100644 (file)
index 0000000..e48869a
--- /dev/null
@@ -0,0 +1,25 @@
+package org.argeo.cms.osgi.useradmin;
+
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.cms.directory.CmsUser;
+import org.argeo.cms.directory.ldap.AbstractLdapDirectory;
+import org.argeo.cms.directory.ldap.DefaultLdapEntry;
+
+/** Directory user implementation */
+class LdifUser extends DefaultLdapEntry implements CmsUser {
+       LdifUser(AbstractLdapDirectory userAdmin, LdapName dn) {
+               super(userAdmin, dn);
+       }
+
+       @Override
+       public String getName() {
+               return getDn().toString();
+       }
+
+       @Override
+       public int getType() {
+               return USER;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/OsUserDirectory.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/OsUserDirectory.java
new file mode 100644 (file)
index 0000000..41277d3
--- /dev/null
@@ -0,0 +1,111 @@
+package org.argeo.cms.osgi.useradmin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.cms.directory.HierarchyUnit;
+import org.argeo.cms.directory.ldap.AbstractLdapDirectory;
+import org.argeo.cms.directory.ldap.AbstractLdapDirectoryDao;
+import org.argeo.cms.directory.ldap.LdapEntry;
+import org.argeo.cms.directory.ldap.LdapEntryWorkingCopy;
+
+/** Pseudo user directory to be used when logging in as OS user. */
+public class OsUserDirectory extends AbstractLdapDirectoryDao {
+       private final String osUsername = System.getProperty("user.name");
+       private final LdapName osUserDn;
+       private final LdapEntry osUser;
+
+       public OsUserDirectory(AbstractLdapDirectory directory) {
+               super(directory);
+               try {
+                       osUserDn = new LdapName(LdapAttr.uid.name() + "=" + osUsername + "," + directory.getUserBaseRdn() + ","
+                                       + directory.getBaseDn());
+//                     Attributes attributes = new BasicAttributes();
+//                     attributes.put(LdapAttrs.uid.name(), osUsername);
+                       osUser = newUser(osUserDn);
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot create system user", e);
+               }
+       }
+
+       @Override
+       public List<LdapName> getDirectGroups(LdapName dn) {
+               return new ArrayList<>();
+       }
+
+       @Override
+       public boolean entryExists(LdapName dn) {
+               return osUserDn.equals(dn);
+       }
+
+       @Override
+       public boolean checkConnection() {
+               return true;
+       }
+
+       @Override
+       public LdapEntry doGetEntry(LdapName key) throws NameNotFoundException {
+               if (osUserDn.equals(key))
+                       return osUser;
+               else
+                       throw new NameNotFoundException("Not an OS role");
+       }
+
+       @Override
+       public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
+               List<LdapEntry> res = new ArrayList<>();
+//             if (f == null || f.match(osUser.getProperties()))
+               res.add(osUser);
+               return res;
+       }
+
+       @Override
+       public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
+               return null;
+       }
+
+       @Override
+       public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
+               return new ArrayList<>();
+       }
+
+       public void prepare(LdapEntryWorkingCopy wc) {
+
+       }
+
+       public void commit(LdapEntryWorkingCopy wc) {
+
+       }
+
+       public void rollback(LdapEntryWorkingCopy wc) {
+
+       }
+
+       @Override
+       public void init() {
+               // TODO Auto-generated method stub
+
+       }
+
+       @Override
+       public void destroy() {
+               // TODO Auto-generated method stub
+
+       }
+
+       @Override
+       public Attributes doGetAttributes(LdapName name) {
+               try {
+                       return doGetEntry(name).getAttributes();
+               } catch (NameNotFoundException e) {
+                       throw new IllegalStateException(name + " doe not exist in " + getDirectory().getBaseDn(), e);
+               }
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/OsUserUtils.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/OsUserUtils.java
new file mode 100644 (file)
index 0000000..f718780
--- /dev/null
@@ -0,0 +1,54 @@
+package org.argeo.cms.osgi.useradmin;
+
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.NoSuchAlgorithmException;
+import java.security.URIParameter;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+/** Log in based on JDK-provided OS integration. */
+public class OsUserUtils {
+       private final static String LOGIN_CONTEXT_USER_NIX = "USER_NIX";
+       private final static String LOGIN_CONTEXT_USER_NT = "USER_NT";
+
+       public static String getOsUsername() {
+               return System.getProperty("user.name");
+       }
+
+       public static LoginContext loginAsSystemUser(Subject subject) {
+               try {
+                       URL jaasConfigurationUrl = OsUserUtils.class.getClassLoader()
+                                       .getResource("org/argeo/osgi/useradmin/jaas-os.cfg");
+                       URIParameter uriParameter = new URIParameter(jaasConfigurationUrl.toURI());
+                       Configuration jaasConfiguration = Configuration.getInstance("JavaLoginConfig", uriParameter);
+                       LoginContext lc = new LoginContext(isWindows() ? LOGIN_CONTEXT_USER_NT : LOGIN_CONTEXT_USER_NIX, subject,
+                                       null, jaasConfiguration);
+                       lc.login();
+                       return lc;
+               } catch (URISyntaxException | NoSuchAlgorithmException | LoginException e) {
+                       throw new RuntimeException("Cannot login as system user", e);
+               }
+       }
+
+       public static void main(String args[]) {
+               Subject subject = new Subject();
+               LoginContext loginContext = loginAsSystemUser(subject);
+               System.out.println(subject);
+               try {
+                       loginContext.logout();
+               } catch (LoginException e) {
+                       // silent
+               }
+       }
+
+       private static boolean isWindows() {
+               return System.getProperty("os.name").startsWith("Windows");
+       }
+
+       private OsUserUtils() {
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/TokenUtils.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/TokenUtils.java
new file mode 100644 (file)
index 0000000..241f609
--- /dev/null
@@ -0,0 +1,87 @@
+package org.argeo.cms.osgi.useradmin;
+
+import static org.argeo.api.acr.ldap.LdapAttr.description;
+import static org.argeo.api.acr.ldap.LdapAttr.owner;
+
+import java.security.Principal;
+import java.time.Instant;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.Subject;
+
+import org.argeo.api.acr.ldap.NamingUtils;
+import org.osgi.service.useradmin.Group;
+
+/**
+ * Canonically implements the Argeo token conventions.
+ */
+public class TokenUtils {
+       public static Set<String> tokensUsed(Subject subject, String tokensBaseDn) {
+               Set<String> res = new HashSet<>();
+               for (Principal principal : subject.getPrincipals()) {
+                       String name = principal.getName();
+                       if (name.endsWith(tokensBaseDn)) {
+                               try {
+                                       LdapName ldapName = new LdapName(name);
+                                       String token = ldapName.getRdn(ldapName.size()).getValue().toString();
+                                       res.add(token);
+                               } catch (InvalidNameException e) {
+                                       throw new IllegalArgumentException("Invalid principal " + principal, e);
+                               }
+                       }
+               }
+               return res;
+       }
+
+       /** The user related to this token group */
+       public static String userDn(Group tokenGroup) {
+               return (String) tokenGroup.getProperties().get(owner.name());
+       }
+
+       public static boolean isExpired(Group tokenGroup) {
+               return isExpired(tokenGroup, Instant.now());
+
+       }
+
+       public static boolean isExpired(Group tokenGroup, Instant instant) {
+               String expiryDateStr = (String) tokenGroup.getProperties().get(description.name());
+               if (expiryDateStr != null) {
+                       Instant expiryDate = NamingUtils.ldapDateToInstant(expiryDateStr);
+                       if (expiryDate.isBefore(instant)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+//     private final String token;
+//
+//     public TokenUtils(String token) {
+//             this.token = token;
+//     }
+//
+//     public String getToken() {
+//             return token;
+//     }
+//
+//     @Override
+//     public int hashCode() {
+//             return token.hashCode();
+//     }
+//
+//     @Override
+//     public boolean equals(Object obj) {
+//             if ((obj instanceof TokenUtils) && ((TokenUtils) obj).token.equals(token))
+//                     return true;
+//             return false;
+//     }
+//
+//     @Override
+//     public String toString() {
+//             return "Token #" + hashCode();
+//     }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/jaas-os.cfg b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/jaas-os.cfg
new file mode 100644 (file)
index 0000000..da04505
--- /dev/null
@@ -0,0 +1,8 @@
+USER_NIX {
+    com.sun.security.auth.module.UnixLoginModule requisite; 
+};
+
+USER_NT {
+    com.sun.security.auth.module.NTLoginModule requisite; 
+};
+
diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/package-info.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/package-info.java
new file mode 100644 (file)
index 0000000..766c59b
--- /dev/null
@@ -0,0 +1,2 @@
+/** LDAP and LDIF based OSGi useradmin implementation. */
+package org.argeo.cms.osgi.useradmin;
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/runtime/DirectoryConf.java b/org.argeo.cms/src/org/argeo/cms/runtime/DirectoryConf.java
new file mode 100644 (file)
index 0000000..a4e44cc
--- /dev/null
@@ -0,0 +1,247 @@
+package org.argeo.cms.runtime;
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.api.acr.ldap.NamingUtils;
+import org.argeo.api.cms.directory.DirectoryDigestUtils;
+import org.argeo.cms.directory.ldap.IpaUtils;
+
+/** Properties used to configure user admins. */
+public enum DirectoryConf {
+       /** Base DN (cannot be configured externally) */
+       baseDn(null),
+
+       /** URI of the underlying resource (cannot be configured externally) */
+       uri(null),
+
+       /** User objectClass */
+       userObjectClass("inetOrgPerson"),
+
+       /** Relative base DN for users */
+       userBase("ou=People"),
+
+       /** Groups objectClass */
+       groupObjectClass("groupOfNames"),
+
+       /** Relative base DN for users */
+       groupBase("ou=Groups"),
+
+       /** Relative base DN for users */
+       systemRoleBase("ou=Roles"),
+
+       /** Read-only source */
+       readOnly(null),
+
+       /** Disabled source */
+       disabled(null),
+
+       /** Authentication realm */
+       realm(null),
+
+       /** Override all passwords with this value (typically for testing purposes) */
+       forcedPassword(null);
+
+       public final static String FACTORY_PID = "org.argeo.osgi.useradmin.config";
+
+       public final static String SCHEME_LDAP = "ldap";
+       public final static String SCHEME_LDAPS = "ldaps";
+       public final static String SCHEME_FILE = "file";
+       public final static String SCHEME_OS = "os";
+       public final static String SCHEME_IPA = "ipa";
+
+       private final static String SECURITY_PRINCIPAL = "java.naming.security.principal";
+       private final static String SECURITY_CREDENTIALS = "java.naming.security.credentials";
+
+       /** The default value. */
+       private Object def;
+
+       DirectoryConf(Object def) {
+               this.def = def;
+       }
+
+       public Object getDefault() {
+               return def;
+       }
+
+       /**
+        * For use as Java property.
+        * 
+        * @deprecated use {@link #name()} instead
+        */
+       @Deprecated
+       public String property() {
+               return name();
+       }
+
+       public String getValue(Dictionary<String, ?> properties) {
+               Object res = getRawValue(properties);
+               if (res == null)
+                       return null;
+               return res.toString();
+       }
+
+       @SuppressWarnings("unchecked")
+       public <T> T getRawValue(Dictionary<String, ?> properties) {
+               Object res = properties.get(name());
+               if (res == null)
+                       res = getDefault();
+               return (T) res;
+       }
+
+       /** @deprecated use {@link #valueOf(String)} instead */
+       @Deprecated
+       public static DirectoryConf local(String property) {
+               return DirectoryConf.valueOf(property);
+       }
+
+       /** Hides host and credentials. */
+       public static URI propertiesAsUri(Dictionary<String, ?> properties) {
+               StringBuilder query = new StringBuilder();
+
+               boolean first = true;
+//             for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements();) {
+//                     String key = keys.nextElement();
+//                     // TODO clarify which keys are relevant (list only the enum?)
+//                     if (!key.equals("service.factoryPid") && !key.equals("cn") && !key.equals("dn")
+//                                     && !key.equals(Constants.SERVICE_PID) && !key.startsWith("java") && !key.equals(baseDn.name())
+//                                     && !key.equals(uri.name()) && !key.equals(Constants.OBJECTCLASS)
+//                                     && !key.equals(Constants.SERVICE_ID) && !key.equals("bundle.id")) {
+//                             if (first)
+//                                     first = false;
+//                             else
+//                                     query.append('&');
+//                             query.append(valueOf(key).name());
+//                             query.append('=').append(properties.get(key).toString());
+//                     }
+//             }
+
+               keys: for (DirectoryConf key : DirectoryConf.values()) {
+                       if (key.equals(baseDn) || key.equals(uri))
+                               continue keys;
+                       Object value = properties.get(key.name());
+                       if (value == null)
+                               continue keys;
+                       if (first)
+                               first = false;
+                       else
+                               query.append('&');
+                       query.append(key.name());
+                       query.append('=').append(value.toString());
+
+               }
+
+               Object bDnObj = properties.get(baseDn.name());
+               String bDn = bDnObj != null ? bDnObj.toString() : null;
+               try {
+                       return new URI(null, null, bDn != null ? '/' + bDn : null, query.length() != 0 ? query.toString() : null,
+                                       null);
+               } catch (URISyntaxException e) {
+                       throw new IllegalArgumentException("Cannot create URI from properties", e);
+               }
+       }
+
+       public static Dictionary<String, Object> uriAsProperties(String uriStr) {
+               try {
+                       Hashtable<String, Object> res = new Hashtable<String, Object>();
+                       URI u = new URI(uriStr);
+                       String scheme = u.getScheme();
+                       if (scheme != null && scheme.equals(SCHEME_IPA)) {
+                               return IpaUtils.convertIpaUri(u);
+//                             scheme = u.getScheme();
+                       }
+                       String path = u.getPath();
+                       // base DN
+                       String bDn = path.substring(path.lastIndexOf('/') + 1, path.length());
+                       if (bDn.equals("") && SCHEME_OS.equals(scheme)) {
+                               bDn = getBaseDnFromHostname();
+                       }
+
+                       if (bDn.endsWith(".ldif"))
+                               bDn = bDn.substring(0, bDn.length() - ".ldif".length());
+
+                       // Normalize base DN as LDAP name
+//                     bDn = new LdapName(bDn).toString();
+
+                       String principal = null;
+                       String credentials = null;
+                       if (scheme != null)
+                               if (scheme.equals(SCHEME_LDAP) || scheme.equals(SCHEME_LDAPS)) {
+                                       // TODO additional checks
+                                       if (u.getUserInfo() != null) {
+                                               String[] userInfo = u.getUserInfo().split(":");
+                                               principal = userInfo.length > 0 ? userInfo[0] : null;
+                                               credentials = userInfo.length > 1 ? userInfo[1] : null;
+                                       }
+                               } else if (scheme.equals(SCHEME_FILE)) {
+                               } else if (scheme.equals(SCHEME_IPA)) {
+                               } else if (scheme.equals(SCHEME_OS)) {
+                               } else
+                                       throw new IllegalArgumentException("Unsupported scheme " + scheme);
+                       Map<String, List<String>> query = NamingUtils.queryToMap(u);
+                       for (String key : query.keySet()) {
+                               DirectoryConf ldapProp = DirectoryConf.valueOf(key);
+                               List<String> values = query.get(key);
+                               if (values.size() == 1) {
+                                       res.put(ldapProp.name(), values.get(0));
+                               } else {
+                                       throw new IllegalArgumentException("Only single values are supported");
+                               }
+                       }
+                       res.put(baseDn.name(), bDn);
+                       if (SCHEME_OS.equals(scheme))
+                               res.put(readOnly.name(), "true");
+                       if (principal != null)
+                               res.put(SECURITY_PRINCIPAL, principal);
+                       if (credentials != null)
+                               res.put(SECURITY_CREDENTIALS, credentials);
+                       if (scheme != null) {// relative URIs are dealt with externally
+                               if (SCHEME_OS.equals(scheme)) {
+                                       res.put(uri.name(), SCHEME_OS + ":///");
+                               } else {
+                                       URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
+                                                       scheme.equals(SCHEME_FILE) ? u.getPath() : null, null, null);
+                                       res.put(uri.name(), bareUri.toString());
+                               }
+                       }
+                       return res;
+               } catch (URISyntaxException e) {
+                       throw new IllegalArgumentException("Cannot convert " + uri + " to properties", e);
+               }
+       }
+
+       private static String getBaseDnFromHostname() {
+               String hostname;
+               try {
+                       hostname = InetAddress.getLocalHost().getHostName();
+               } catch (UnknownHostException e) {
+                       hostname = "localhost.localdomain";
+               }
+               int dotIdx = hostname.indexOf('.');
+               if (dotIdx >= 0) {
+                       String domain = hostname.substring(dotIdx + 1, hostname.length());
+                       String bDn = ("." + domain).replaceAll("\\.", ",dc=");
+                       bDn = bDn.substring(1, bDn.length());
+                       return bDn;
+               } else {
+                       return "dc=" + hostname;
+               }
+       }
+
+       /**
+        * Hash the base DN in order to have a deterministic string to be used as a cn
+        * for the underlying user directory.
+        */
+       public static String baseDnHash(Dictionary<String, Object> properties) {
+               String bDn = (String) properties.get(baseDn.name());
+               if (bDn == null)
+                       throw new IllegalStateException("No baseDn in " + properties);
+               return DirectoryDigestUtils.sha1str(bDn);
+       }
+}
index e473d27994ff8f4e467461166b3b6523c7043fb5..76775fed8060f912bed6a725df629113fc8f211e 100644 (file)
@@ -9,21 +9,21 @@ import org.argeo.api.acr.spi.ProvidedRepository;
 import org.argeo.api.cms.CmsContext;
 import org.argeo.api.cms.CmsDeployment;
 import org.argeo.api.cms.CmsState;
+import org.argeo.api.cms.directory.CmsUserManager;
+import org.argeo.api.cms.transaction.SimpleTransactionManager;
+import org.argeo.api.cms.transaction.WorkControl;
+import org.argeo.api.cms.transaction.WorkTransaction;
+import org.argeo.api.register.Component;
+import org.argeo.api.register.ComponentRegister;
+import org.argeo.api.register.SimpleRegister;
 import org.argeo.api.uuid.UuidFactory;
-import org.argeo.cms.CmsUserManager;
 import org.argeo.cms.acr.CmsUuidFactory;
-import org.argeo.cms.internal.auth.CmsUserManagerImpl;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
 import org.argeo.cms.internal.runtime.CmsDeploymentImpl;
 import org.argeo.cms.internal.runtime.CmsStateImpl;
 import org.argeo.cms.internal.runtime.CmsUserAdmin;
+import org.argeo.cms.internal.runtime.CmsUserManagerImpl;
 import org.argeo.cms.internal.runtime.DeployedContentRepository;
-import org.argeo.util.register.Component;
-import org.argeo.util.register.ComponentRegister;
-import org.argeo.util.register.SimpleRegister;
-import org.argeo.util.transaction.SimpleTransactionManager;
-import org.argeo.util.transaction.WorkControl;
-import org.argeo.util.transaction.WorkTransaction;
 import org.osgi.service.useradmin.UserAdmin;
 
 /**
diff --git a/org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java b/org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java
deleted file mode 100644 (file)
index 3de2e14..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-package org.argeo.cms.security;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.CharArrayWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.security.Provider;
-import java.security.Security;
-import java.util.Arrays;
-import java.util.Iterator;
-
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.TextOutputCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-import org.argeo.api.cms.CmsAuth;
-import org.argeo.util.CurrentSubject;
-import org.argeo.util.StreamUtils;
-
-/** username / password based keyring. TODO internationalize */
-public abstract class AbstractKeyring implements Keyring, CryptoKeyring {
-       // public final static String DEFAULT_KEYRING_LOGIN_CONTEXT = "KEYRING";
-
-       // private String loginContextName = DEFAULT_KEYRING_LOGIN_CONTEXT;
-       private CallbackHandler defaultCallbackHandler;
-
-       private String charset = "UTF-8";
-
-       /**
-        * Default provider is bouncy castle, in order to have consistent behaviour
-        * across implementations
-        */
-       private String securityProviderName = "BC";
-
-       /**
-        * Whether the keyring has already been created in the past with a master
-        * password
-        */
-       protected abstract Boolean isSetup();
-
-       /**
-        * Setup the keyring persistently, {@link #isSetup()} must return true
-        * afterwards
-        */
-       protected abstract void setup(char[] password);
-
-       /** Populates the key spec callback */
-       protected abstract void handleKeySpecCallback(PBEKeySpecCallback pbeCallback);
-
-       protected abstract void encrypt(String path, InputStream unencrypted);
-
-       protected abstract InputStream decrypt(String path);
-
-       /** Triggers lazy initialization */
-       protected SecretKey getSecretKey(char[] password) {
-               Subject subject = CurrentSubject.current();
-               if (subject == null)
-                       throw new IllegalStateException("Current subject cannot be null");
-               // we assume only one secrete key is available
-               Iterator<SecretKey> iterator = subject.getPrivateCredentials(SecretKey.class).iterator();
-               if (!iterator.hasNext() || password != null) {// not initialized
-                       CallbackHandler callbackHandler = password == null ? new KeyringCallbackHandler()
-                                       : new PasswordProvidedCallBackHandler(password);
-                       ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
-                       Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
-                       try {
-                               LoginContext loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_KEYRING, subject, callbackHandler);
-                               loginContext.login();
-                               // FIXME will login even if password is wrong
-                               iterator = subject.getPrivateCredentials(SecretKey.class).iterator();
-                               return iterator.next();
-                       } catch (LoginException e) {
-                               throw new IllegalStateException("Keyring login failed", e);
-                       } finally {
-                               Thread.currentThread().setContextClassLoader(currentContextClassLoader);
-                       }
-
-               } else {
-                       SecretKey secretKey = iterator.next();
-                       if (iterator.hasNext())
-                               throw new IllegalStateException("More than one secret key in private credentials");
-                       return secretKey;
-               }
-       }
-
-       public InputStream getAsStream(String path) {
-               return decrypt(path);
-       }
-
-       public void set(String path, InputStream in) {
-               encrypt(path, in);
-       }
-
-       public char[] getAsChars(String path) {
-               // InputStream in = getAsStream(path);
-               // CharArrayWriter writer = null;
-               // Reader reader = null;
-               try (InputStream in = getAsStream(path);
-                               CharArrayWriter writer = new CharArrayWriter();
-                               Reader reader = new InputStreamReader(in, charset);) {
-                       StreamUtils.copy(reader, writer);
-                       return writer.toCharArray();
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot decrypt to char array", e);
-               } finally {
-                       // IOUtils.closeQuietly(reader);
-                       // IOUtils.closeQuietly(in);
-                       // IOUtils.closeQuietly(writer);
-               }
-       }
-
-       public void set(String path, char[] arr) {
-               // ByteArrayOutputStream out = new ByteArrayOutputStream();
-               // ByteArrayInputStream in = null;
-               // Writer writer = null;
-               try (ByteArrayOutputStream out = new ByteArrayOutputStream();
-                               Writer writer = new OutputStreamWriter(out, charset);) {
-                       // writer = new OutputStreamWriter(out, charset);
-                       writer.write(arr);
-                       writer.flush();
-                       // in = new ByteArrayInputStream(out.toByteArray());
-                       try (ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());) {
-                               set(path, in);
-                       }
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot encrypt to char array", e);
-               } finally {
-                       // IOUtils.closeQuietly(writer);
-                       // IOUtils.closeQuietly(out);
-                       // IOUtils.closeQuietly(in);
-               }
-       }
-
-       public void unlock(char[] password) {
-               if (!isSetup())
-                       setup(password);
-               SecretKey secretKey = getSecretKey(password);
-               if (secretKey == null)
-                       throw new IllegalStateException("Could not unlock keyring");
-       }
-
-       protected Provider getSecurityProvider() {
-               return Security.getProvider(securityProviderName);
-       }
-
-       public void setDefaultCallbackHandler(CallbackHandler defaultCallbackHandler) {
-               this.defaultCallbackHandler = defaultCallbackHandler;
-       }
-
-       public void setCharset(String charset) {
-               this.charset = charset;
-       }
-
-       public void setSecurityProviderName(String securityProviderName) {
-               this.securityProviderName = securityProviderName;
-       }
-
-       // @Deprecated
-       // protected static byte[] hash(char[] password, byte[] salt, Integer
-       // iterationCount) {
-       // ByteArrayOutputStream out = null;
-       // OutputStreamWriter writer = null;
-       // try {
-       // out = new ByteArrayOutputStream();
-       // writer = new OutputStreamWriter(out, "UTF-8");
-       // writer.write(password);
-       // MessageDigest pwDigest = MessageDigest.getInstance("SHA-256");
-       // pwDigest.reset();
-       // pwDigest.update(salt);
-       // byte[] btPass = pwDigest.digest(out.toByteArray());
-       // for (int i = 0; i < iterationCount; i++) {
-       // pwDigest.reset();
-       // btPass = pwDigest.digest(btPass);
-       // }
-       // return btPass;
-       // } catch (Exception e) {
-       // throw new CmsException("Cannot hash", e);
-       // } finally {
-       // IOUtils.closeQuietly(out);
-       // IOUtils.closeQuietly(writer);
-       // }
-       //
-       // }
-
-       /**
-        * Convenience method using the underlying callback to ask for a password
-        * (typically used when the password is not saved in the keyring)
-        */
-       protected char[] ask() {
-               PasswordCallback passwordCb = new PasswordCallback("Password", false);
-               Callback[] dialogCbs = new Callback[] { passwordCb };
-               try {
-                       defaultCallbackHandler.handle(dialogCbs);
-                       char[] password = passwordCb.getPassword();
-                       return password;
-               } catch (Exception e) {
-                       throw new IllegalStateException("Cannot ask for a password", e);
-               }
-
-       }
-
-       class KeyringCallbackHandler implements CallbackHandler {
-               public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-                       // checks
-                       if (callbacks.length != 2)
-                               throw new IllegalArgumentException(
-                                               "Keyring requires 2 and only 2 callbacks: {PasswordCallback,PBEKeySpecCallback}");
-                       if (!(callbacks[0] instanceof PasswordCallback))
-                               throw new UnsupportedCallbackException(callbacks[0]);
-                       if (!(callbacks[1] instanceof PBEKeySpecCallback))
-                               throw new UnsupportedCallbackException(callbacks[0]);
-
-                       PasswordCallback passwordCb = (PasswordCallback) callbacks[0];
-                       PBEKeySpecCallback pbeCb = (PBEKeySpecCallback) callbacks[1];
-
-                       if (isSetup()) {
-                               Callback[] dialogCbs = new Callback[] { passwordCb };
-                               defaultCallbackHandler.handle(dialogCbs);
-                       } else {// setup keyring
-                               TextOutputCallback textCb1 = new TextOutputCallback(TextOutputCallback.INFORMATION,
-                                               "Enter a master password which will protect your private data");
-                               TextOutputCallback textCb2 = new TextOutputCallback(TextOutputCallback.INFORMATION,
-                                               "(for example your credentials to third-party services)");
-                               TextOutputCallback textCb3 = new TextOutputCallback(TextOutputCallback.INFORMATION,
-                                               "Don't forget this password since the data cannot be read without it");
-                               PasswordCallback confirmPasswordCb = new PasswordCallback("Confirm password", false);
-                               // first try
-                               Callback[] dialogCbs = new Callback[] { textCb1, textCb2, textCb3, passwordCb, confirmPasswordCb };
-                               defaultCallbackHandler.handle(dialogCbs);
-
-                               // if passwords different, retry (except if cancelled)
-                               while (passwordCb.getPassword() != null
-                                               && !Arrays.equals(passwordCb.getPassword(), confirmPasswordCb.getPassword())) {
-                                       TextOutputCallback textCb = new TextOutputCallback(TextOutputCallback.ERROR,
-                                                       "The passwords do not match");
-                                       dialogCbs = new Callback[] { textCb, passwordCb, confirmPasswordCb };
-                                       defaultCallbackHandler.handle(dialogCbs);
-                               }
-
-                               if (passwordCb.getPassword() != null) {// not cancelled
-                                       setup(passwordCb.getPassword());
-                               }
-                       }
-
-                       if (passwordCb.getPassword() != null)
-                               handleKeySpecCallback(pbeCb);
-               }
-
-       }
-
-       class PasswordProvidedCallBackHandler implements CallbackHandler {
-               private final char[] password;
-
-               public PasswordProvidedCallBackHandler(char[] password) {
-                       this.password = password;
-               }
-
-               @Override
-               public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-                       // checks
-                       if (callbacks.length != 2)
-                               throw new IllegalArgumentException(
-                                               "Keyring requires 2 and only 2 callbacks: {PasswordCallback,PBEKeySpecCallback}");
-                       if (!(callbacks[0] instanceof PasswordCallback))
-                               throw new UnsupportedCallbackException(callbacks[0]);
-                       if (!(callbacks[1] instanceof PBEKeySpecCallback))
-                               throw new UnsupportedCallbackException(callbacks[0]);
-
-                       PasswordCallback passwordCb = (PasswordCallback) callbacks[0];
-                       passwordCb.setPassword(password);
-                       PBEKeySpecCallback pbeCb = (PBEKeySpecCallback) callbacks[1];
-                       handleKeySpecCallback(pbeCb);
-               }
-
-       }
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/security/ChecksumFactory.java b/org.argeo.cms/src/org/argeo/cms/security/ChecksumFactory.java
deleted file mode 100644 (file)
index 7344f01..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-package org.argeo.cms.security;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Base64;
-import java.util.zip.Checksum;
-
-/** Allows to fine tune how files are read. */
-public class ChecksumFactory {
-       private int regionSize = 10 * 1024 * 1024;
-
-       public byte[] digest(Path path, final String algo) {
-               try {
-                       final MessageDigest md = MessageDigest.getInstance(algo);
-                       if (Files.isDirectory(path)) {
-                               long begin = System.currentTimeMillis();
-                               Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
-
-                                       @Override
-                                       public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                                               if (!Files.isDirectory(file)) {
-                                                       byte[] digest = digest(file, algo);
-                                                       md.update(digest);
-                                               }
-                                               return FileVisitResult.CONTINUE;
-                                       }
-
-                               });
-                               byte[] digest = md.digest();
-                               long duration = System.currentTimeMillis() - begin;
-                               System.out.println(printBase64Binary(digest) + " " + path + " (" + duration / 1000 + "s)");
-                               return digest;
-                       } else {
-                               long begin = System.nanoTime();
-                               long length = -1;
-                               try (FileChannel channel = (FileChannel) Files.newByteChannel(path);) {
-                                       length = channel.size();
-                                       long cursor = 0;
-                                       while (cursor < length) {
-                                               long effectiveSize = Math.min(regionSize, length - cursor);
-                                               MappedByteBuffer mb = channel.map(FileChannel.MapMode.READ_ONLY, cursor, effectiveSize);
-                                               // md.update(mb);
-                                               byte[] buffer = new byte[1024];
-                                               while (mb.hasRemaining()) {
-                                                       mb.get(buffer);
-                                                       md.update(buffer);
-                                               }
-
-                                               // sub digest
-                                               // mb.flip();
-                                               // MessageDigest subMd =
-                                               // MessageDigest.getInstance(algo);
-                                               // subMd.update(mb);
-                                               // byte[] subDigest = subMd.digest();
-                                               // System.out.println(" -> " + cursor);
-                                               // System.out.println(IOUtils.encodeHexString(subDigest));
-                                               // System.out.println(new BigInteger(1,
-                                               // subDigest).toString(16));
-                                               // System.out.println(new BigInteger(1, subDigest)
-                                               // .toString(Character.MAX_RADIX));
-                                               // System.out.println(printBase64Binary(subDigest));
-
-                                               cursor = cursor + regionSize;
-                                       }
-                                       byte[] digest = md.digest();
-                                       long duration = System.nanoTime() - begin;
-                                       System.out.println(printBase64Binary(digest) + " " + path.getFileName() + " (" + duration / 1000000
-                                                       + "ms, " + (length / 1024) + "kB, " + (length / (duration / 1000000)) * 1000 / (1024 * 1024)
-                                                       + " MB/s)");
-                                       return digest;
-                               }
-                       }
-               } catch (NoSuchAlgorithmException | IOException e) {
-                       throw new IllegalStateException("Cannot digest " + path, e);
-               }
-       }
-
-       /** Whether the file should be mapped. */
-       protected boolean mapFile(FileChannel fileChannel) throws IOException {
-               long size = fileChannel.size();
-               if (size > (regionSize / 10))
-                       return true;
-               return false;
-       }
-
-       public long checksum(Path path, Checksum crc) {
-               final int bufferSize = 2 * 1024 * 1024;
-               long begin = System.currentTimeMillis();
-               try (FileChannel channel = (FileChannel) Files.newByteChannel(path);) {
-                       byte[] bytes = new byte[bufferSize];
-                       long length = channel.size();
-                       long cursor = 0;
-                       while (cursor < length) {
-                               long effectiveSize = Math.min(regionSize, length - cursor);
-                               MappedByteBuffer mb = channel.map(FileChannel.MapMode.READ_ONLY, cursor, effectiveSize);
-                               int nGet;
-                               while (mb.hasRemaining()) {
-                                       nGet = Math.min(mb.remaining(), bufferSize);
-                                       mb.get(bytes, 0, nGet);
-                                       crc.update(bytes, 0, nGet);
-                               }
-                               cursor = cursor + regionSize;
-                       }
-                       return crc.getValue();
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot checksum " + path, e);
-               } finally {
-                       long duration = System.currentTimeMillis() - begin;
-                       System.out.println(duration / 1000 + "s");
-               }
-       }
-
-       public static void main(String... args) {
-               ChecksumFactory cf = new ChecksumFactory();
-               // Path path =
-               // Paths.get("/home/mbaudier/apache-maven-3.2.3-bin.tar.gz");
-               Path path;
-               if (args.length > 0) {
-                       path = Paths.get(args[0]);
-               } else {
-                       path = Paths.get("/home/mbaudier/Downloads/torrents/CentOS-7-x86_64-DVD-1503-01/"
-                                       + "CentOS-7-x86_64-DVD-1503-01.iso");
-               }
-               // long adler = cf.checksum(path, new Adler32());
-               // System.out.format("Adler=%d%n", adler);
-               // long crc = cf.checksum(path, new CRC32());
-               // System.out.format("CRC=%d%n", crc);
-               String algo = "SHA1";
-               byte[] digest = cf.digest(path, algo);
-               System.out.println(algo + " " + printBase64Binary(digest));
-               System.out.println(algo + " " + new BigInteger(1, digest).toString(16));
-               // String sha1 = printBase64Binary(cf.digest(path, "SHA1"));
-               // System.out.format("SHA1=%s%n", sha1);
-       }
-
-       private static String printBase64Binary(byte[] arr) {
-               return Base64.getEncoder().encodeToString(arr);
-       }
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/security/CryptoKeyring.java b/org.argeo.cms/src/org/argeo/cms/security/CryptoKeyring.java
deleted file mode 100644 (file)
index df26c6b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.argeo.cms.security;
-
-/**
- * Marker interface for an advanced keyring based on cryptography.
- */
-public interface CryptoKeyring extends Keyring {
-       public void changePassword(char[] oldPassword, char[] newPassword);
-
-       public void unlock(char[] password);
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/security/Keyring.java b/org.argeo.cms/src/org/argeo/cms/security/Keyring.java
deleted file mode 100644 (file)
index 53740c6..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.argeo.cms.security;
-
-import java.io.InputStream;
-
-/**
- * Access to private (typically encrypted) data. The keyring is responsible for
- * retrieving the necessary credentials. <b>Experimental. This API may
- * change.</b>
- */
-public interface Keyring {
-       /**
-        * Returns the confidential information as chars. Must ask for it if it is
-        * not stored.
-        */
-       public char[] getAsChars(String path);
-
-       /**
-        * Returns the confidential information as a stream. Must ask for it if it
-        * is not stored.
-        */
-       public InputStream getAsStream(String path);
-
-       public void set(String path, char[] arr);
-
-       public void set(String path, InputStream in);
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/security/PBEKeySpecCallback.java b/org.argeo.cms/src/org/argeo/cms/security/PBEKeySpecCallback.java
deleted file mode 100644 (file)
index 13e8d75..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.argeo.cms.security;
-
-import javax.crypto.spec.PBEKeySpec;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.PasswordCallback;
-
-/**
- * All information required to set up a {@link PBEKeySpec} bar the password
- * itself (use a {@link PasswordCallback})
- */
-public class PBEKeySpecCallback implements Callback {
-       private String secretKeyFactory;
-       private byte[] salt;
-       private Integer iterationCount;
-       /** Can be null for some algorithms */
-       private Integer keyLength;
-       /** Can be null, will trigger secret key encryption if not */
-       private String secretKeyEncryption;
-
-       private String encryptedPasswordHashCipher;
-       private byte[] encryptedPasswordHash;
-
-       public void set(String secretKeyFactory, byte[] salt,
-                       Integer iterationCount, Integer keyLength,
-                       String secretKeyEncryption) {
-               this.secretKeyFactory = secretKeyFactory;
-               this.salt = salt;
-               this.iterationCount = iterationCount;
-               this.keyLength = keyLength;
-               this.secretKeyEncryption = secretKeyEncryption;
-//             this.encryptedPasswordHashCipher = encryptedPasswordHashCipher;
-//             this.encryptedPasswordHash = encryptedPasswordHash;
-       }
-
-       public String getSecretKeyFactory() {
-               return secretKeyFactory;
-       }
-
-       public byte[] getSalt() {
-               return salt;
-       }
-
-       public Integer getIterationCount() {
-               return iterationCount;
-       }
-
-       public Integer getKeyLength() {
-               return keyLength;
-       }
-
-       public String getSecretKeyEncryption() {
-               return secretKeyEncryption;
-       }
-
-       public String getEncryptedPasswordHashCipher() {
-               return encryptedPasswordHashCipher;
-       }
-
-       public byte[] getEncryptedPasswordHash() {
-               return encryptedPasswordHash;
-       }
-
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/security/package-info.java b/org.argeo.cms/src/org/argeo/cms/security/package-info.java
deleted file mode 100644 (file)
index e994054..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo CMS reusable security components. */
-package org.argeo.cms.security;
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/ArrayTabularRow.java b/org.argeo.cms/src/org/argeo/cms/tabular/ArrayTabularRow.java
deleted file mode 100644 (file)
index cfd4827..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.argeo.cms.tabular;
-
-import java.util.List;
-
-/** Minimal tabular row wrapping an {@link Object} array */
-public class ArrayTabularRow implements TabularRow {
-       private final Object[] arr;
-
-       public ArrayTabularRow(List<?> objs) {
-               this.arr = objs.toArray();
-       }
-
-       public Object get(Integer col) {
-               return arr[col];
-       }
-
-       public int size() {
-               return arr.length;
-       }
-
-       public Object[] toArray() {
-               return arr;
-       }
-
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/TabularColumn.java b/org.argeo.cms/src/org/argeo/cms/tabular/TabularColumn.java
deleted file mode 100644 (file)
index 7f7ac1e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.argeo.cms.tabular;
-
-/** The column in a tabular content */
-public class TabularColumn {
-       private String name;
-       /**
-        * JCR types, see
-        * http://www.day.com/maven/javax.jcr/javadocs/jcr-2.0/index.html
-        * ?javax/jcr/PropertyType.html
-        */
-       private Integer type;
-
-       /** column with default type */
-       public TabularColumn(String name) {
-               super();
-               this.name = name;
-       }
-
-       public TabularColumn(String name, Integer type) {
-               super();
-               this.name = name;
-               this.type = type;
-       }
-
-       public String getName() {
-               return name;
-       }
-
-       public void setName(String name) {
-               this.name = name;
-       }
-
-       public Integer getType() {
-               return type;
-       }
-
-       public void setType(Integer type) {
-               this.type = type;
-       }
-
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/TabularContent.java b/org.argeo.cms/src/org/argeo/cms/tabular/TabularContent.java
deleted file mode 100644 (file)
index c6d2ab8..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.argeo.cms.tabular;
-
-import java.util.List;
-
-/**
- * Content organized as a table, possibly with headers. Only JCR types are
- * supported even though there is not direct dependency on JCR.
- */
-public interface TabularContent {
-       /** The headers of this table or <code>null</code> is none available. */
-       public List<TabularColumn> getColumns();
-
-       public TabularRowIterator read();
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/TabularRow.java b/org.argeo.cms/src/org/argeo/cms/tabular/TabularRow.java
deleted file mode 100644 (file)
index 69b9732..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.argeo.cms.tabular;
-
-/** A row of tabular data */
-public interface TabularRow {
-       /** The value at this column index */
-       public Object get(Integer col);
-
-       /** The raw objects (direct references) */
-       public Object[] toArray();
-
-       /** Number of columns */
-       public int size();
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/TabularRowIterator.java b/org.argeo.cms/src/org/argeo/cms/tabular/TabularRowIterator.java
deleted file mode 100644 (file)
index 7ad8719..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.argeo.cms.tabular;
-
-import java.util.Iterator;
-
-/** Navigation of rows */
-public interface TabularRowIterator extends Iterator<TabularRow> {
-       /**
-        * Current row number, has to be incremented by each call to next() ; starts at 0, will
-        * therefore be 1 for the first row returned.
-        */
-       public Long getCurrentRowNumber();
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/TabularWriter.java b/org.argeo.cms/src/org/argeo/cms/tabular/TabularWriter.java
deleted file mode 100644 (file)
index 34fc85b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.argeo.cms.tabular;
-
-
-/** Write to a tabular content */
-public interface TabularWriter {
-       /** Append a new row of data */
-       public void appendRow(Object[] row);
-
-       /** Finish persisting data and release resources */
-       public void close();
-}
diff --git a/org.argeo.cms/src/org/argeo/cms/tabular/package-info.java b/org.argeo.cms/src/org/argeo/cms/tabular/package-info.java
deleted file mode 100644 (file)
index 6cb48d0..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Tabular format API. */
-package org.argeo.cms.tabular;
\ No newline at end of file
diff --git a/org.argeo.cms/src/org/argeo/cms/util/CompositeString.java b/org.argeo.cms/src/org/argeo/cms/util/CompositeString.java
new file mode 100644 (file)
index 0000000..8ea16f7
--- /dev/null
@@ -0,0 +1,164 @@
+package org.argeo.cms.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.StringTokenizer;
+
+/** A name that can be expressed with various conventions. */
+public class CompositeString {
+       public final static Character UNDERSCORE = Character.valueOf('_');
+       public final static Character SPACE = Character.valueOf(' ');
+       public final static Character DASH = Character.valueOf('-');
+
+       private final String[] parts;
+
+       // optimisation
+       private final int hashCode;
+
+       public CompositeString(String str) {
+               Objects.requireNonNull(str, "String cannot be null");
+               if ("".equals(str.trim()))
+                       throw new IllegalArgumentException("String cannot be empty");
+               if (!str.equals(str.trim()))
+                       throw new IllegalArgumentException("String must be trimmed");
+               this.parts = toParts(str);
+               hashCode = hashCode(this.parts);
+       }
+
+       public String toString(char separator, boolean upperCase) {
+               StringBuilder sb = null;
+               for (String part : parts) {
+                       if (sb == null) {
+                               sb = new StringBuilder();
+                       } else {
+                               sb.append(separator);
+                       }
+                       sb.append(upperCase ? part.toUpperCase() : part);
+               }
+               return sb.toString();
+       }
+
+       public String toStringCaml(boolean firstCharUpperCase) {
+               StringBuilder sb = null;
+               for (String part : parts) {
+                       if (sb == null) {// first
+                               sb = new StringBuilder();
+                               sb.append(firstCharUpperCase ? Character.toUpperCase(part.charAt(0)) : part.charAt(0));
+                       } else {
+                               sb.append(Character.toUpperCase(part.charAt(0)));
+                       }
+
+                       if (part.length() > 1)
+                               sb.append(part.substring(1));
+               }
+               return sb.toString();
+       }
+
+       @Override
+       public int hashCode() {
+               return hashCode;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj == null || !(obj instanceof CompositeString))
+                       return false;
+
+               CompositeString other = (CompositeString) obj;
+               return Arrays.equals(parts, other.parts);
+       }
+
+       @Override
+       public String toString() {
+               return toString(DASH, false);
+       }
+
+       public static String[] toParts(String str) {
+               Character separator = null;
+               if (str.indexOf(UNDERSCORE) >= 0) {
+                       checkNo(str, SPACE);
+                       checkNo(str, DASH);
+                       separator = UNDERSCORE;
+               } else if (str.indexOf(DASH) >= 0) {
+                       checkNo(str, SPACE);
+                       checkNo(str, UNDERSCORE);
+                       separator = DASH;
+               } else if (str.indexOf(SPACE) >= 0) {
+                       checkNo(str, DASH);
+                       checkNo(str, UNDERSCORE);
+                       separator = SPACE;
+               }
+
+               List<String> res = new ArrayList<>();
+               if (separator != null) {
+                       StringTokenizer st = new StringTokenizer(str, separator.toString());
+                       while (st.hasMoreTokens()) {
+                               res.add(st.nextToken().toLowerCase());
+                       }
+               } else {
+                       // single
+                       String strLowerCase = str.toLowerCase();
+                       if (str.toUpperCase().equals(str) || strLowerCase.equals(str))
+                               return new String[] { strLowerCase };
+
+                       // CAML
+                       StringBuilder current = null;
+                       for (char c : str.toCharArray()) {
+                               if (Character.isUpperCase(c)) {
+                                       if (current != null)
+                                               res.add(current.toString());
+                                       current = new StringBuilder();
+                               }
+                               if (current == null)// first char is lower case
+                                       current = new StringBuilder();
+                               current.append(Character.toLowerCase(c));
+                       }
+                       res.add(current.toString());
+               }
+               return res.toArray(new String[res.size()]);
+       }
+
+       private static void checkNo(String str, Character c) {
+               if (str.indexOf(c) >= 0) {
+                       throw new IllegalArgumentException("Only one kind of sperator is allowed");
+               }
+       }
+
+       private static int hashCode(String[] parts) {
+               int hashCode = 0;
+               for (String part : parts) {
+                       hashCode = hashCode + part.hashCode();
+               }
+               return hashCode;
+       }
+
+       static boolean smokeTests() {
+               CompositeString plainName = new CompositeString("NAME");
+               assert "name".equals(plainName.toString());
+               assert "NAME".equals(plainName.toString(UNDERSCORE, true));
+               assert "name".equals(plainName.toString(UNDERSCORE, false));
+               assert "name".equals(plainName.toStringCaml(false));
+               assert "Name".equals(plainName.toStringCaml(true));
+
+               CompositeString camlName = new CompositeString("myComplexName");
+
+               assert new CompositeString("my-complex-name").equals(camlName);
+               assert new CompositeString("MY_COMPLEX_NAME").equals(camlName);
+               assert new CompositeString("My complex Name").equals(camlName);
+               assert new CompositeString("MyComplexName").equals(camlName);
+
+               assert "my-complex-name".equals(camlName.toString());
+               assert "MY_COMPLEX_NAME".equals(camlName.toString(UNDERSCORE, true));
+               assert "my_complex_name".equals(camlName.toString(UNDERSCORE, false));
+               assert "myComplexName".equals(camlName.toStringCaml(false));
+               assert "MyComplexName".equals(camlName.toStringCaml(true));
+
+               return CompositeString.class.desiredAssertionStatus();
+       }
+
+       public static void main(String[] args) {
+               System.out.println(smokeTests());
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/CsvParser.java b/org.argeo.cms/src/org/argeo/cms/util/CsvParser.java
new file mode 100644 (file)
index 0000000..f22a1e4
--- /dev/null
@@ -0,0 +1,242 @@
+package org.argeo.cms.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Parses a CSV file interpreting the first line as a header. The
+ * {@link #parse(InputStream)} method and the setters are synchronized so that
+ * the object cannot be modified when parsing.
+ */
+public abstract class CsvParser {
+       private char separator = ',';
+       private char quote = '\"';
+
+       private Boolean noHeader = false;
+       private Boolean strictLineAsLongAsHeader = true;
+
+       /**
+        * Actually process a parsed line. If
+        * {@link #setStrictLineAsLongAsHeader(Boolean)} is true (default) the header
+        * and the tokens are guaranteed to have the same size.
+        * 
+        * @param lineNumber the current line number, starts at 1 (the header, if header
+        *                   processing is enabled, the first line otherwise)
+        * @param header     the read-only header or null if
+        *                   {@link #setNoHeader(Boolean)} is true (default is false)
+        * @param tokens     the parsed tokens
+        */
+       protected abstract void processLine(Integer lineNumber, List<String> header, List<String> tokens);
+
+       /**
+        * Parses the CSV file (stream is closed at the end)
+        * 
+        * @param in the stream to parse
+        * 
+        * @deprecated Use {@link #parse(InputStream, Charset)} instead.
+        */
+       @Deprecated
+       public synchronized void parse(InputStream in) {
+               parse(in, (Charset) null);
+       }
+
+       /**
+        * Parses the CSV file (stream is closed at the end)
+        * 
+        * @param in       the stream to parse
+        * @param encoding the encoding to use.
+        * 
+        * @deprecated Use {@link #parse(InputStream, Charset)} instead.
+        */
+       @Deprecated
+       public synchronized void parse(InputStream in, String encoding) {
+               Reader reader;
+               if (encoding == null)
+                       reader = new InputStreamReader(in);
+               else
+                       try {
+                               reader = new InputStreamReader(in, encoding);
+                       } catch (UnsupportedEncodingException e) {
+                               throw new IllegalArgumentException(e);
+                       }
+               parse(reader);
+       }
+
+       /**
+        * Parses the CSV file (stream is closed at the end)
+        * 
+        * @param in      the stream to parse
+        * @param charset the charset to use
+        */
+       public synchronized void parse(InputStream in, Charset charset) {
+               Reader reader;
+               if (charset == null)
+                       reader = new InputStreamReader(in);
+               else
+                       reader = new InputStreamReader(in, charset);
+               parse(reader);
+       }
+
+       /**
+        * Parses the CSV file (stream is closed at the end)
+        * 
+        * @param reader the reader to use (it will be buffered)
+        */
+       public synchronized void parse(Reader reader) {
+               Integer lineCount = 0;
+               try (BufferedReader bufferedReader = new BufferedReader(reader)) {
+                       List<String> header = null;
+                       if (!noHeader) {
+                               String headerStr = bufferedReader.readLine();
+                               if (headerStr == null)// empty file
+                                       return;
+                               lineCount++;
+                               header = new ArrayList<String>();
+                               StringBuffer currStr = new StringBuffer("");
+                               Boolean wasInquote = false;
+                               while (parseLine(headerStr, header, currStr, wasInquote)) {
+                                       headerStr = bufferedReader.readLine();
+                                       if (headerStr == null)
+                                               break;
+                                       wasInquote = true;
+                               }
+                               header = Collections.unmodifiableList(header);
+                       }
+
+                       String line = null;
+                       lines: while ((line = bufferedReader.readLine()) != null) {
+                               line = preProcessLine(line);
+                               if (line == null) {
+                                       // skip line
+                                       continue lines;
+                               }
+                               lineCount++;
+                               List<String> tokens = new ArrayList<String>();
+                               StringBuffer currStr = new StringBuffer("");
+                               Boolean wasInquote = false;
+                               sublines: while (parseLine(line, tokens, currStr, wasInquote)) {
+                                       line = bufferedReader.readLine();
+                                       if (line == null)
+                                               break sublines;
+                                       wasInquote = true;
+                               }
+                               if (!noHeader && strictLineAsLongAsHeader) {
+                                       int headerSize = header.size();
+                                       int tokenSize = tokens.size();
+                                       if (tokenSize == 1 && line.trim().equals(""))
+                                               continue lines;// empty line
+                                       if (headerSize != tokenSize) {
+                                               throw new IllegalStateException("Token size " + tokenSize + " is different from header size "
+                                                               + headerSize + " at line " + lineCount + ", line: " + line + ", header: " + header
+                                                               + ", tokens: " + tokens);
+                                       }
+                               }
+                               processLine(lineCount, header, tokens);
+                       }
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot parse CSV file (line: " + lineCount + ")", e);
+               }
+       }
+
+       /**
+        * Called before each (logical) line is processed, giving a change to modify it
+        * (typically for cleaning dirty files). To be overridden, return the line
+        * unchanged by default. Skip the line if 'null' is returned.
+        */
+       protected String preProcessLine(String line) {
+               return line;
+       }
+
+       /**
+        * Parses a line character by character for performance purpose
+        * 
+        * @return whether to continue parsing this line
+        */
+       protected Boolean parseLine(String str, List<String> tokens, StringBuffer currStr, Boolean wasInquote) {
+               if (wasInquote)
+                       currStr.append('\n');
+
+               char[] arr = str.toCharArray();
+               boolean inQuote = wasInquote;
+               for (int i = 0; i < arr.length; i++) {
+                       char c = arr[i];
+                       if (c == separator) {
+                               if (!inQuote) {
+                                       tokens.add(currStr.toString());
+//                                     currStr.delete(0, currStr.length());
+                                       currStr.setLength(0);
+                                       currStr.trimToSize();
+                               } else {
+                                       // we don't remove separator that are in a quoted substring
+                                       // System.out
+                                       // .println("IN QUOTE, got a separator: [" + c + "]");
+                                       currStr.append(c);
+                               }
+                       } else if (c == quote) {
+                               if (inQuote && (i + 1) < arr.length && arr[i + 1] == quote) {
+                                       // case of double quote
+                                       currStr.append(quote);
+                                       i++;
+                               } else {// standard
+                                       inQuote = inQuote ? false : true;
+                               }
+                       } else {
+                               currStr.append(c);
+                       }
+               }
+
+               if (!inQuote) {
+                       tokens.add(currStr.toString());
+                       // System.out.println("# TOKEN: " + currStr);
+               }
+               // if (inQuote)
+               // throw new ArgeoException("Missing quote at the end of the line "
+               // + str + " (parsed: " + tokens + ")");
+               if (inQuote)
+                       return true;
+               else
+                       return false;
+               // return tokens;
+       }
+
+       public char getSeparator() {
+               return separator;
+       }
+
+       public synchronized void setSeparator(char separator) {
+               this.separator = separator;
+       }
+
+       public char getQuote() {
+               return quote;
+       }
+
+       public synchronized void setQuote(char quote) {
+               this.quote = quote;
+       }
+
+       public Boolean getNoHeader() {
+               return noHeader;
+       }
+
+       public synchronized void setNoHeader(Boolean noHeader) {
+               this.noHeader = noHeader;
+       }
+
+       public Boolean getStrictLineAsLongAsHeader() {
+               return strictLineAsLongAsHeader;
+       }
+
+       public synchronized void setStrictLineAsLongAsHeader(Boolean strictLineAsLongAsHeader) {
+               this.strictLineAsLongAsHeader = strictLineAsLongAsHeader;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/CsvParserWithLinesAsMap.java b/org.argeo.cms/src/org/argeo/cms/util/CsvParserWithLinesAsMap.java
new file mode 100644 (file)
index 0000000..0a0382c
--- /dev/null
@@ -0,0 +1,36 @@
+package org.argeo.cms.util;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * CSV parser allowing to process lines as maps whose keys are the header
+ * fields.
+ */
+public abstract class CsvParserWithLinesAsMap extends CsvParser {
+
+       /**
+        * Actually processes a line.
+        * 
+        * @param lineNumber the current line number, starts at 1 (the header, if header
+        *                   processing is enabled, the first lien otherwise)
+        * @param line       the parsed tokens as a map whose keys are the header fields
+        */
+       protected abstract void processLine(Integer lineNumber, Map<String, String> line);
+
+       protected final void processLine(Integer lineNumber, List<String> header, List<String> tokens) {
+               if (header == null)
+                       throw new IllegalArgumentException("Only CSV with header is supported");
+               Map<String, String> line = new HashMap<String, String>();
+               for (int i = 0; i < header.size(); i++) {
+                       String key = header.get(i);
+                       String value = null;
+                       if (i < tokens.size())
+                               value = tokens.get(i);
+                       line.put(key, value);
+               }
+               processLine(lineNumber, line);
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/CsvWriter.java b/org.argeo.cms/src/org/argeo/cms/util/CsvWriter.java
new file mode 100644 (file)
index 0000000..902e6bb
--- /dev/null
@@ -0,0 +1,156 @@
+package org.argeo.cms.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.List;
+
+/** Write in CSV format. */
+public class CsvWriter {
+       private final Writer out;
+
+       private char separator = ',';
+       private char quote = '\"';
+
+       /**
+        * Creates a CSV writer.
+        * 
+        * @param out the stream to write to. Caller is responsible for closing it.
+        * 
+        * @deprecated Use {@link #CsvWriter(OutputStream, Charset)} instead.
+        * 
+        */
+       @Deprecated
+       public CsvWriter(OutputStream out) {
+               this.out = new OutputStreamWriter(out);
+       }
+
+       /**
+        * Creates a CSV writer.
+        * 
+        * @param out      the stream to write to. Caller is responsible for closing it.
+        * @param encoding the encoding to use.
+        * 
+        * @deprecated Use {@link #CsvWriter(OutputStream, Charset)} instead.
+        */
+       @Deprecated
+       public CsvWriter(OutputStream out, String encoding) {
+               try {
+                       this.out = new OutputStreamWriter(out, encoding);
+               } catch (UnsupportedEncodingException e) {
+                       throw new IllegalArgumentException(e);
+               }
+       }
+
+       /**
+        * Creates a CSV writer.
+        * 
+        * @param out     the stream to write to. Caller is responsible for closing it.
+        * @param charset the charset to use
+        */
+       public CsvWriter(OutputStream out, Charset charset) {
+               this.out = new OutputStreamWriter(out, charset);
+       }
+
+       /**
+        * Creates a CSV writer.
+        * 
+        * @param out the stream to write to. Caller is responsible for closing it.
+        */
+       public CsvWriter(Writer writer) {
+               this.out = writer;
+       }
+
+       /**
+        * Write a CSV line. Also used to write a header if needed (this is transparent
+        * for the CSV writer): simply call it first, before writing the lines.
+        */
+       public void writeLine(List<?> tokens) {
+               try {
+                       Iterator<?> it = tokens.iterator();
+                       while (it.hasNext()) {
+                               Object obj = it.next();
+                               writeToken(obj != null ? obj.toString() : null);
+                               if (it.hasNext())
+                                       out.write(separator);
+                       }
+                       out.write('\n');
+                       out.flush();
+               } catch (IOException e) {
+                       throw new RuntimeException("Could not write " + tokens, e);
+               }
+       }
+
+       /**
+        * Write a CSV line. Also used to write a header if needed (this is transparent
+        * for the CSV writer): simply call it first, before writing the lines.
+        */
+       public void writeLine(Object... tokens) {
+               try {
+                       for (int i = 0; i < tokens.length; i++) {
+                               if (tokens[i] == null) {
+                                       writeToken(null);
+                               } else {
+                                       writeToken(tokens[i].toString());
+                               }
+                               if (i != (tokens.length - 1))
+                                       out.write(separator);
+                       }
+                       out.write('\n');
+                       out.flush();
+               } catch (IOException e) {
+                       throw new RuntimeException("Could not write " + tokens, e);
+               }
+       }
+
+       protected void writeToken(String token) throws IOException {
+               if (token == null) {
+                       // TODO configure how to deal with null
+                       out.write("");
+                       return;
+               }
+               // +2 for possible quotes, another +2 assuming there would be an already
+               // quoted string where quotes needs to be duplicated
+               // another +2 for safety
+               // we don't want to increase buffer size while writing
+               StringBuffer buf = new StringBuffer(token.length() + 6);
+               char[] arr = token.toCharArray();
+               boolean shouldQuote = false;
+               for (char c : arr) {
+                       if (!shouldQuote) {
+                               if (c == separator)
+                                       shouldQuote = true;
+                               if (c == '\n')
+                                       shouldQuote = true;
+                       }
+
+                       if (c == quote) {
+                               shouldQuote = true;
+                               // duplicate quote
+                               buf.append(quote);
+                       }
+
+                       // generic case
+                       buf.append(c);
+               }
+
+               if (shouldQuote == true)
+                       out.write(quote);
+               out.write(buf.toString());
+               if (shouldQuote == true)
+                       out.write(quote);
+       }
+
+       public void setSeparator(char separator) {
+               this.separator = separator;
+       }
+
+       public void setQuote(char quote) {
+               this.quote = quote;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/CurrentSubject.java b/org.argeo.cms/src/org/argeo/cms/util/CurrentSubject.java
new file mode 100644 (file)
index 0000000..6a3dcbc
--- /dev/null
@@ -0,0 +1,65 @@
+package org.argeo.cms.util;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionException;
+
+import javax.security.auth.Subject;
+
+/**
+ * Prepare evolution of Java APIs introduced in JDK 18, as these static methods
+ * will be added to {@link Subject}.
+ */
+@SuppressWarnings("removal")
+public class CurrentSubject {
+
+       private final static boolean useThreadLocal = Boolean
+                       .parseBoolean(System.getProperty("jdk.security.auth.subject.useTL"));
+
+       private final static InheritableThreadLocal<Subject> current = new InheritableThreadLocal<>();
+
+       public static Subject current() {
+               if (useThreadLocal) {
+                       return current.get();
+               } else {// legacy
+                       Subject subject = Subject.getSubject(AccessController.getContext());
+                       return subject;
+               }
+       }
+
+       public static <T> T callAs(Subject subject, Callable<T> action) {
+               if (useThreadLocal) {
+                       Subject previous = current();
+                       current.set(subject);
+                       try {
+                               return action.call();
+                       } catch (Exception e) {
+                               throw new CompletionException("Failed to execute action for " + subject, e);
+                       } finally {
+                               current.set(previous);
+                       }
+               } else {// legacy
+                       try {
+                               return Subject.doAs(subject, new PrivilegedExceptionAction<T>() {
+
+                                       @Override
+                                       public T run() throws Exception {
+                                               return action.call();
+                                       }
+
+                               });
+                       } catch (PrivilegedActionException e) {
+                               throw new CompletionException("Failed to execute action for " + subject, e.getCause());
+                       } catch (Exception e) {
+                               throw new CompletionException("Failed to execute action for " + subject, e);
+                       }
+               }
+       }
+
+       /** Singleton. */
+       private CurrentSubject() {
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/DictionaryKeys.java b/org.argeo.cms/src/org/argeo/cms/util/DictionaryKeys.java
new file mode 100644 (file)
index 0000000..a9f6a31
--- /dev/null
@@ -0,0 +1,42 @@
+package org.argeo.cms.util;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+/**
+ * Access the keys of a {@link String}-keyed {@link Dictionary} (common throughout
+ * the OSGi APIs) as an {@link Iterable} so that they are easily usable in
+ * for-each loops.
+ */
+class DictionaryKeys implements Iterable<String> {
+       private final Dictionary<String, ?> dictionary;
+
+       public DictionaryKeys(Dictionary<String, ?> dictionary) {
+               this.dictionary = dictionary;
+       }
+
+       @Override
+       public Iterator<String> iterator() {
+               return new KeyIterator(dictionary.keys());
+       }
+
+       private static class KeyIterator implements Iterator<String> {
+               private final Enumeration<String> keys;
+
+               KeyIterator(Enumeration<String> keys) {
+                       this.keys = keys;
+               }
+
+               @Override
+               public boolean hasNext() {
+                       return keys.hasMoreElements();
+               }
+
+               @Override
+               public String next() {
+                       return keys.nextElement();
+               }
+
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/DigestUtils.java b/org.argeo.cms/src/org/argeo/cms/util/DigestUtils.java
new file mode 100644 (file)
index 0000000..047749f
--- /dev/null
@@ -0,0 +1,202 @@
+package org.argeo.cms.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/** Utilities around cryptographic digests */
+public class DigestUtils {
+       public final static String MD5 = "MD5";
+       public final static String SHA1 = "SHA1";
+       public final static String SHA256 = "SHA-256";
+       public final static String SHA512 = "SHA-512";
+
+       private static Boolean debug = false;
+       // TODO: make it configurable
+       private final static Integer byteBufferCapacity = 100 * 1024;// 100 KB
+
+       public static byte[] sha1(byte[]... bytes) {
+               try {
+                       MessageDigest digest = MessageDigest.getInstance(SHA1);
+                       for (byte[] arr : bytes)
+                               digest.update(arr);
+                       byte[] checksum = digest.digest();
+                       return checksum;
+               } catch (NoSuchAlgorithmException e) {
+                       throw new UnsupportedOperationException("SHA1 is not avalaible", e);
+               }
+       }
+
+       public static byte[] digestAsBytes(String algorithm, byte[]... bytes) {
+               try {
+                       MessageDigest digest = MessageDigest.getInstance(algorithm);
+                       for (byte[] arr : bytes)
+                               digest.update(arr);
+                       byte[] checksum = digest.digest();
+                       return checksum;
+               } catch (NoSuchAlgorithmException e) {
+                       throw new UnsupportedOperationException("Cannot digest with algorithm " + algorithm, e);
+               }
+       }
+
+       public static String digest(String algorithm, byte[]... bytes) {
+               return toHexString(digestAsBytes(algorithm, bytes));
+       }
+
+       public static String digest(String algorithm, InputStream in) {
+               try {
+                       MessageDigest digest = MessageDigest.getInstance(algorithm);
+                       // ReadableByteChannel channel = Channels.newChannel(in);
+                       // ByteBuffer bb = ByteBuffer.allocateDirect(byteBufferCapacity);
+                       // while (channel.read(bb) > 0)
+                       // digest.update(bb);
+                       byte[] buffer = new byte[byteBufferCapacity];
+                       int read = 0;
+                       while ((read = in.read(buffer)) > 0) {
+                               digest.update(buffer, 0, read);
+                       }
+
+                       byte[] checksum = digest.digest();
+                       String res = toHexString(checksum);
+                       return res;
+               } catch (NoSuchAlgorithmException e) {
+                       throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e);
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               } finally {
+                       StreamUtils.closeQuietly(in);
+               }
+       }
+
+       public static String digest(String algorithm, File file) {
+               FileInputStream fis = null;
+               FileChannel fc = null;
+               try {
+                       fis = new FileInputStream(file);
+                       fc = fis.getChannel();
+
+                       // Get the file's size and then map it into memory
+                       int sz = (int) fc.size();
+                       ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz);
+                       return digest(algorithm, bb);
+               } catch (IOException e) {
+                       throw new IllegalArgumentException("Cannot digest " + file + " with algorithm " + algorithm, e);
+               } finally {
+                       StreamUtils.closeQuietly(fis);
+                       if (fc.isOpen())
+                               try {
+                                       fc.close();
+                               } catch (IOException e) {
+                                       // silent
+                               }
+               }
+       }
+
+       protected static String digest(String algorithm, ByteBuffer bb) {
+               long begin = System.currentTimeMillis();
+               try {
+                       MessageDigest digest = MessageDigest.getInstance(algorithm);
+                       digest.update(bb);
+                       byte[] checksum = digest.digest();
+                       String res = toHexString(checksum);
+                       long end = System.currentTimeMillis();
+                       if (debug)
+                               System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
+                       return res;
+               } catch (NoSuchAlgorithmException e) {
+                       throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e);
+               }
+       }
+
+       public static String sha1hex(Path path) {
+               return digest(SHA1, path, byteBufferCapacity);
+       }
+
+       public static String digest(String algorithm, Path path, long bufferSize) {
+               byte[] digest = digestAsBytes(algorithm, path, bufferSize);
+               return toHexString(digest);
+       }
+
+       public static byte[] digestAsBytes(String algorithm, Path file, long bufferSize) {
+               long begin = System.currentTimeMillis();
+               try {
+                       MessageDigest md = MessageDigest.getInstance(algorithm);
+                       FileChannel fc = FileChannel.open(file);
+                       long fileSize = Files.size(file);
+                       if (fileSize <= bufferSize) {
+                               ByteBuffer bb = fc.map(MapMode.READ_ONLY, 0, fileSize);
+                               md.update(bb);
+                       } else {
+                               long lastCycle = (fileSize / bufferSize) - 1;
+                               long position = 0;
+                               for (int i = 0; i <= lastCycle; i++) {
+                                       ByteBuffer bb;
+                                       if (i != lastCycle) {
+                                               bb = fc.map(MapMode.READ_ONLY, position, bufferSize);
+                                               position = position + bufferSize;
+                                       } else {
+                                               bb = fc.map(MapMode.READ_ONLY, position, fileSize - position);
+                                               position = fileSize;
+                                       }
+                                       md.update(bb);
+                               }
+                       }
+                       long end = System.currentTimeMillis();
+                       if (debug)
+                               System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
+                       return md.digest();
+               } catch (NoSuchAlgorithmException e) {
+                       throw new IllegalArgumentException("Cannot digest " + file + "  with algorithm " + algorithm, e);
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot digest " + file + "  with algorithm " + algorithm, e);
+               }
+       }
+
+       public static void main(String[] args) {
+               File file;
+               if (args.length > 0)
+                       file = new File(args[0]);
+               else {
+                       System.err.println("Usage: <file> [<algorithm>]" + " (see http://java.sun.com/j2se/1.5.0/"
+                                       + "docs/guide/security/CryptoSpec.html#AppA)");
+                       return;
+               }
+
+               if (args.length > 1) {
+                       String algorithm = args[1];
+                       System.out.println(digest(algorithm, file));
+               } else {
+                       String algorithm = "MD5";
+                       System.out.println(algorithm + ": " + digest(algorithm, file));
+                       algorithm = "SHA";
+                       System.out.println(algorithm + ": " + digest(algorithm, file));
+                       System.out.println(algorithm + ": " + sha1hex(file.toPath()));
+                       algorithm = "SHA-256";
+                       System.out.println(algorithm + ": " + digest(algorithm, file));
+                       algorithm = "SHA-512";
+                       System.out.println(algorithm + ": " + digest(algorithm, file));
+               }
+       }
+
+       final private static char[] hexArray = "0123456789abcdef".toCharArray();
+
+       /** Converts a byte array to an hex String. */
+       public static String toHexString(byte[] bytes) {
+               char[] hexChars = new char[bytes.length * 2];
+               for (int j = 0; j < bytes.length; j++) {
+                       int v = bytes[j] & 0xFF;
+                       hexChars[j * 2] = hexArray[v >>> 4];
+                       hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+               }
+               return new String(hexChars);
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/DirH.java b/org.argeo.cms/src/org/argeo/cms/util/DirH.java
new file mode 100644 (file)
index 0000000..2596c61
--- /dev/null
@@ -0,0 +1,116 @@
+package org.argeo.cms.util;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** Hashes the hashes of the files in a directory. */
+public class DirH {
+
+       private final static Charset charset = Charset.forName("UTF-16");
+       private final static long bufferSize = 200 * 1024 * 1024;
+       private final static String algorithm = "SHA";
+
+       private final static byte EOL = (byte) '\n';
+       private final static byte SPACE = (byte) ' ';
+
+       private final int hashSize;
+
+       private final byte[][] hashes;
+       private final byte[][] fileNames;
+       private final byte[] digest;
+       private final byte[] dirName;
+
+       /**
+        * @param dirName can be null or empty
+        */
+       private DirH(byte[][] hashes, byte[][] fileNames, byte[] dirName) {
+               if (hashes.length != fileNames.length)
+                       throw new IllegalArgumentException(hashes.length + " hashes and " + fileNames.length + " file names");
+               this.hashes = hashes;
+               this.fileNames = fileNames;
+               this.dirName = dirName == null ? new byte[0] : dirName;
+               if (hashes.length == 0) {// empty dir
+                       hashSize = 20;
+                       // FIXME what is the digest of an empty dir?
+                       digest = new byte[hashSize];
+                       Arrays.fill(digest, SPACE);
+                       return;
+               }
+               hashSize = hashes[0].length;
+               for (int i = 0; i < hashes.length; i++) {
+                       if (hashes[i].length != hashSize)
+                               throw new IllegalArgumentException(
+                                               "Hash size for " + new String(fileNames[i], charset) + " is " + hashes[i].length);
+               }
+
+               try {
+                       MessageDigest md = MessageDigest.getInstance(algorithm);
+                       for (int i = 0; i < hashes.length; i++) {
+                               md.update(this.hashes[i]);
+                               md.update(SPACE);
+                               md.update(this.fileNames[i]);
+                               md.update(EOL);
+                       }
+                       digest = md.digest();
+               } catch (NoSuchAlgorithmException e) {
+                       throw new IllegalArgumentException("Cannot digest", e);
+               }
+       }
+
+       public void print(PrintStream out) {
+               out.print(DigestUtils.toHexString(digest));
+               if (dirName.length > 0) {
+                       out.print(' ');
+                       out.print(new String(dirName, charset));
+               }
+               out.print('\n');
+               for (int i = 0; i < hashes.length; i++) {
+                       out.print(DigestUtils.toHexString(hashes[i]));
+                       out.print(' ');
+                       out.print(new String(fileNames[i], charset));
+                       out.print('\n');
+               }
+       }
+
+       public static DirH digest(Path dir) {
+               try (DirectoryStream<Path> files = Files.newDirectoryStream(dir)) {
+                       List<byte[]> hs = new ArrayList<byte[]>();
+                       List<String> fNames = new ArrayList<>();
+                       for (Path file : files) {
+                               if (!Files.isDirectory(file)) {
+                                       byte[] digest = DigestUtils.digestAsBytes(algorithm, file, bufferSize);
+                                       hs.add(digest);
+                                       fNames.add(file.getFileName().toString());
+                               }
+                       }
+
+                       byte[][] fileNames = new byte[fNames.size()][];
+                       for (int i = 0; i < fNames.size(); i++) {
+                               fileNames[i] = fNames.get(i).getBytes(charset);
+                       }
+                       byte[][] hashes = hs.toArray(new byte[hs.size()][]);
+                       return new DirH(hashes, fileNames, dir.toString().getBytes(charset));
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot digest " + dir, e);
+               }
+       }
+
+       public static void main(String[] args) {
+               try {
+                       DirH dirH = DirH.digest(Paths.get("/home/mbaudier/tmp/"));
+                       dirH.print(System.out);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/ExceptionsChain.java b/org.argeo.cms/src/org/argeo/cms/util/ExceptionsChain.java
new file mode 100644 (file)
index 0000000..e71cfb3
--- /dev/null
@@ -0,0 +1,90 @@
+package org.argeo.cms.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Serialisable wrapper of a {@link Throwable}. typically to be written as XML
+ * or JSON in a server error response.
+ */
+public class ExceptionsChain {
+       private List<SystemException> exceptions = new ArrayList<>();
+
+       public ExceptionsChain() {
+       }
+
+       public ExceptionsChain(Throwable exception) {
+               writeException(exception);
+       }
+
+       /** recursive */
+       protected void writeException(Throwable exception) {
+               SystemException systemException = new SystemException(exception);
+               exceptions.add(systemException);
+               Throwable cause = exception.getCause();
+               if (cause != null)
+                       writeException(cause);
+       }
+
+       public List<SystemException> getExceptions() {
+               return exceptions;
+       }
+
+       public void setExceptions(List<SystemException> exceptions) {
+               this.exceptions = exceptions;
+       }
+
+       /** An exception in the chain. */
+       public static class SystemException {
+               private String type;
+               private String message;
+               private List<String> stackTrace;
+
+               public SystemException() {
+               }
+
+               public SystemException(Throwable exception) {
+                       this.type = exception.getClass().getName();
+                       this.message = exception.getMessage();
+                       this.stackTrace = new ArrayList<>();
+                       StackTraceElement[] elems = exception.getStackTrace();
+                       for (int i = 0; i < elems.length; i++)
+                               stackTrace.add("at " + elems[i].toString());
+               }
+
+               public String getType() {
+                       return type;
+               }
+
+               public void setType(String type) {
+                       this.type = type;
+               }
+
+               public String getMessage() {
+                       return message;
+               }
+
+               public void setMessage(String message) {
+                       this.message = message;
+               }
+
+               public List<String> getStackTrace() {
+                       return stackTrace;
+               }
+
+               public void setStackTrace(List<String> stackTrace) {
+                       this.stackTrace = stackTrace;
+               }
+
+               @Override
+               public String toString() {
+                       return "System exception: " + type + ", " + message + ", " + stackTrace;
+               }
+
+       }
+
+       @Override
+       public String toString() {
+               return exceptions.toString();
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/FsUtils.java b/org.argeo.cms/src/org/argeo/cms/util/FsUtils.java
new file mode 100644 (file)
index 0000000..26c05b6
--- /dev/null
@@ -0,0 +1,78 @@
+package org.argeo.cms.util;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+/** Utilities around the standard Java file abstractions. */
+public class FsUtils {
+
+       /** Deletes this path, recursively if needed. */
+       public static void copyDirectory(Path source, Path target) {
+               if (!Files.exists(source) || !Files.isDirectory(source))
+                       throw new IllegalArgumentException(source + " is not a directory");
+               if (Files.exists(target) && !Files.isDirectory(target))
+                       throw new IllegalArgumentException(target + " is not a directory");
+               try {
+                       Files.createDirectories(target);
+                       Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
+
+                               @Override
+                               public FileVisitResult preVisitDirectory(Path directory, BasicFileAttributes attrs) throws IOException {
+                                       Path relativePath = source.relativize(directory);
+                                       Path targetDirectory = target.resolve(relativePath);
+                                       if (!Files.exists(targetDirectory))
+                                               Files.createDirectory(targetDirectory);
+                                       return FileVisitResult.CONTINUE;
+                               }
+
+                               @Override
+                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                                       Path relativePath = source.relativize(file);
+                                       Path targetFile = target.resolve(relativePath);
+                                       Files.copy(file, targetFile);
+                                       return FileVisitResult.CONTINUE;
+                               }
+                       });
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot copy " + source + " to " + target, e);
+               }
+
+       }
+
+       /**
+        * Deletes this path, recursively if needed. Does nothing if the path does not
+        * exist.
+        */
+       public static void delete(Path path) {
+               try {
+                       if (!Files.exists(path))
+                               return;
+                       Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+                               @Override
+                               public FileVisitResult postVisitDirectory(Path directory, IOException e) throws IOException {
+                                       if (e != null)
+                                               throw e;
+                                       Files.delete(directory);
+                                       return FileVisitResult.CONTINUE;
+                               }
+
+                               @Override
+                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                                       Files.delete(file);
+                                       return FileVisitResult.CONTINUE;
+                               }
+                       });
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot delete " + path, e);
+               }
+       }
+
+       /** Singleton. */
+       private FsUtils() {
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/LangUtils.java b/org.argeo.cms/src/org/argeo/cms/util/LangUtils.java
new file mode 100644 (file)
index 0000000..0e21427
--- /dev/null
@@ -0,0 +1,331 @@
+package org.argeo.cms.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+/** Utilities around Java basic features. */
+public class LangUtils {
+       /*
+        * NON-API OSGi
+        */
+       /**
+        * Returns an array with the names of the provided classes. Useful when
+        * registering services with multiple interfaces in OSGi.
+        */
+       public static String[] names(Class<?>... clzz) {
+               String[] res = new String[clzz.length];
+               for (int i = 0; i < clzz.length; i++)
+                       res[i] = clzz[i].getName();
+               return res;
+       }
+
+//     /*
+//      * MAP
+//      */
+//     /**
+//      * Creates a new {@link Map} with one key-value pair. Key should not be null,
+//      * but if the value is null, it returns an empty {@link Map}.
+//      * 
+//      * @deprecated Use {@link Collections#singletonMap(Object, Object)} instead.
+//      */
+//     @Deprecated
+//     public static Map<String, Object> map(String key, Object value) {
+//             assert key != null;
+//             HashMap<String, Object> props = new HashMap<>();
+//             if (value != null)
+//                     props.put(key, value);
+//             return props;
+//     }
+
+       /*
+        * DICTIONARY
+        */
+
+       /**
+        * Creates a new {@link Dictionary} with one key-value pair. Key should not be
+        * null, but if the value is null, it returns an empty {@link Dictionary}.
+        */
+       public static Dictionary<String, Object> dict(String key, Object value) {
+               assert key != null;
+               Hashtable<String, Object> props = new Hashtable<>();
+               if (value != null)
+                       props.put(key, value);
+               return props;
+       }
+
+       /** @deprecated Use {@link #dict(String, Object)} instead. */
+       @Deprecated
+       public static Dictionary<String, Object> dico(String key, Object value) {
+               return dict(key, value);
+       }
+
+       /** Converts a {@link Dictionary} to a {@link Map} of strings. */
+       public static Map<String, String> dictToStringMap(Dictionary<String, ?> properties) {
+               if (properties == null) {
+                       return null;
+               }
+               Map<String, String> res = new HashMap<>(properties.size());
+               Enumeration<String> keys = properties.keys();
+               while (keys.hasMoreElements()) {
+                       String key = keys.nextElement();
+                       res.put(key, properties.get(key).toString());
+               }
+               return res;
+       }
+
+       /** Converts a {@link Dictionary} to a {@link Map}. */
+       public static Map<String, Object> dictToMap(Dictionary<String, ?> properties) {
+               if (properties == null) {
+                       return null;
+               }
+               Map<String, Object> res = new HashMap<>(properties.size());
+               Enumeration<String> keys = properties.keys();
+               while (keys.hasMoreElements()) {
+                       String key = keys.nextElement();
+                       res.put(key, properties.get(key));
+               }
+               return res;
+       }
+
+       /**
+        * Get a string property from this map, expecting to find it, or
+        * <code>null</code> if not found.
+        */
+       public static String get(Map<String, ?> map, String key) {
+               Object res = map.get(key);
+               if (res == null)
+                       return null;
+               return res.toString();
+       }
+
+       /**
+        * Get a string property from this map, expecting to find it.
+        * 
+        * @throws IllegalArgumentException if the key was not found
+        */
+       public static String getNotNull(Map<String, ?> map, String key) {
+               Object res = map.get(key);
+               if (res == null)
+                       throw new IllegalArgumentException("Map " + map + " should contain key " + key);
+               return res.toString();
+       }
+
+       /**
+        * Wraps the keys of the provided {@link Dictionary} as an {@link Iterable}.
+        */
+       public static Iterable<String> keys(Dictionary<String, ?> props) {
+               assert props != null;
+               return new DictionaryKeys(props);
+       }
+
+       static String toJson(Dictionary<String, ?> props) {
+               return toJson(props, false);
+       }
+
+       static String toJson(Dictionary<String, ?> props, boolean pretty) {
+               StringBuilder sb = new StringBuilder();
+               sb.append('{');
+               if (pretty)
+                       sb.append('\n');
+               Enumeration<String> keys = props.keys();
+               while (keys.hasMoreElements()) {
+                       String key = keys.nextElement();
+                       if (pretty)
+                               sb.append(' ');
+                       sb.append('\"').append(key).append('\"');
+                       if (pretty)
+                               sb.append(" : ");
+                       else
+                               sb.append(':');
+                       sb.append('\"').append(props.get(key)).append('\"');
+                       if (keys.hasMoreElements())
+                               sb.append(", ");
+                       if (pretty)
+                               sb.append('\n');
+               }
+               sb.append('}');
+               return sb.toString();
+       }
+
+       static void storeAsProperties(Dictionary<String, Object> props, Path path) throws IOException {
+               if (props == null)
+                       throw new IllegalArgumentException("Props cannot be null");
+               Properties toStore = new Properties();
+               for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
+                       String key = keys.nextElement();
+                       toStore.setProperty(key, props.get(key).toString());
+               }
+               try (OutputStream out = Files.newOutputStream(path)) {
+                       toStore.store(out, null);
+               }
+       }
+
+       static void appendAsLdif(String dnBase, String dnKey, Dictionary<String, Object> props, Path path)
+                       throws IOException {
+               if (props == null)
+                       throw new IllegalArgumentException("Props cannot be null");
+               Object dnValue = props.get(dnKey);
+               String dnStr = dnKey + '=' + dnValue + ',' + dnBase;
+               LdapName dn;
+               try {
+                       dn = new LdapName(dnStr);
+               } catch (InvalidNameException e) {
+                       throw new IllegalArgumentException("Cannot interpret DN " + dnStr, e);
+               }
+               if (dnValue == null)
+                       throw new IllegalArgumentException("DN key " + dnKey + " must have a value");
+               try (Writer writer = Files.newBufferedWriter(path, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
+                       writer.append("\ndn: ");
+                       writer.append(dn.toString());
+                       writer.append('\n');
+                       for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
+                               String key = keys.nextElement();
+                               Object value = props.get(key);
+                               writer.append(key);
+                               writer.append(": ");
+                               // FIXME deal with binary and multiple values
+                               writer.append(value.toString());
+                               writer.append('\n');
+                       }
+               }
+       }
+
+       static Dictionary<String, Object> loadFromProperties(Path path) throws IOException {
+               Properties toLoad = new Properties();
+               try (InputStream in = Files.newInputStream(path)) {
+                       toLoad.load(in);
+               }
+               Dictionary<String, Object> res = new Hashtable<String, Object>();
+               for (Object key : toLoad.keySet())
+                       res.put(key.toString(), toLoad.get(key));
+               return res;
+       }
+
+       /*
+        * COLLECTIONS
+        */
+       /**
+        * Convert a comma-separated separated {@link String} or a {@link String} array
+        * to a {@link List} of {@link String}, trimming them. Useful to quickly
+        * interpret OSGi services properties.
+        * 
+        * @return a {@link List} containing the trimmed {@link String}s, or an empty
+        *         {@link List} if the argument was <code>null</code>.
+        */
+       public static List<String> toStringList(Object value) {
+               List<String> values = new ArrayList<>();
+               if (value == null)
+                       return values;
+               String[] arr;
+               if (value instanceof String) {
+                       arr = ((String) value).split(",");
+               } else if (value instanceof String[]) {
+                       arr = (String[]) value;
+               } else {
+                       throw new IllegalArgumentException("Unsupported value type " + value.getClass());
+               }
+               for (String str : arr) {
+                       values.add(str.trim());
+               }
+               return values;
+       }
+
+       /** Size of an {@link Iterable}, optimised if it is a {@link Collection}. */
+       public static int size(Iterable<?> iterable) {
+               if (iterable instanceof Collection)
+                       return ((Collection<?>) iterable).size();
+
+               int size = 0;
+               for (Iterator<?> it = iterable.iterator(); it.hasNext(); size++)
+                       it.next();
+               return size;
+       }
+
+       public static <T> T getAt(Iterable<T> iterable, int index) {
+               if (iterable instanceof List) {
+                       List<T> lst = ((List<T>) iterable);
+                       if (index >= lst.size())
+                               throw new IllegalArgumentException("Index " + index + " is not available (size is " + lst.size() + ")");
+                       return lst.get(index);
+               }
+               int i = 0;
+               for (Iterator<T> it = iterable.iterator(); it.hasNext(); i++) {
+                       if (i == index)
+                               return it.next();
+                       else
+                               it.next();
+               }
+               throw new IllegalArgumentException("Index " + index + " is not available (size is " + i + ")");
+       }
+
+       /*
+        * EXCEPTIONS
+        */
+       /**
+        * Chain the messages of all causes (one per line, <b>starts with a line
+        * return</b>) without all the stack
+        */
+       public static String chainCausesMessages(Throwable t) {
+               StringBuffer buf = new StringBuffer();
+               chainCauseMessage(buf, t);
+               return buf.toString();
+       }
+
+       /** Recursive chaining of messages */
+       private static void chainCauseMessage(StringBuffer buf, Throwable t) {
+               buf.append('\n').append(' ').append(t.getClass().getCanonicalName()).append(": ").append(t.getMessage());
+               if (t.getCause() != null)
+                       chainCauseMessage(buf, t.getCause());
+       }
+
+       /*
+        * TIME
+        */
+       /** Formats time elapsed since start. */
+       public static String since(ZonedDateTime start) {
+               ZonedDateTime now = ZonedDateTime.now();
+               return duration(start, now);
+       }
+
+       /** Formats a duration. */
+       public static String duration(Temporal start, Temporal end) {
+               long count = ChronoUnit.DAYS.between(start, end);
+               if (count != 0)
+                       return count > 1 ? count + " days" : count + " day";
+               count = ChronoUnit.HOURS.between(start, end);
+               if (count != 0)
+                       return count > 1 ? count + " hours" : count + " hours";
+               count = ChronoUnit.MINUTES.between(start, end);
+               if (count != 0)
+                       return count > 1 ? count + " minutes" : count + " minute";
+               count = ChronoUnit.SECONDS.between(start, end);
+               return count > 1 ? count + " seconds" : count + " second";
+       }
+
+       /** Singleton constructor. */
+       private LangUtils() {
+
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/OS.java b/org.argeo.cms/src/org/argeo/cms/util/OS.java
new file mode 100644 (file)
index 0000000..c63d7a1
--- /dev/null
@@ -0,0 +1,65 @@
+package org.argeo.cms.util;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/** When OS specific informations are needed. */
+public class OS {
+       public final static OS LOCAL = new OS();
+
+       private final String arch, name, version;
+
+       /** The OS of the running JVM */
+       protected OS() {
+               arch = System.getProperty("os.arch");
+               name = System.getProperty("os.name");
+               version = System.getProperty("os.version");
+       }
+
+       public String getArch() {
+               return arch;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public String getVersion() {
+               return version;
+       }
+
+       public boolean isMSWindows() {
+               // only MS Windows would use such an horrendous separator...
+               return File.separatorChar == '\\';
+       }
+
+       public String[] getDefaultShellCommand() {
+               if (!isMSWindows())
+                       return new String[] { "/bin/bash", "-l", "-i" };
+               else
+                       return new String[] { "cmd.exe", "/C" };
+       }
+
+       public static long getJvmPid() {
+               return ProcessHandle.current().pid();
+//             String pidAndHost = ManagementFactory.getRuntimeMXBean().getName();
+//             return Integer.parseInt(pidAndHost.substring(0, pidAndHost.indexOf('@')));
+       }
+
+       /**
+        * Get the runtime directory. It will be the environment variable
+        * XDG_RUNTIME_DIR if it is set, or ~/.cache/argeo if not.
+        */
+       public static Path getRunDir() {
+               Path runDir;
+               String xdgRunDir = System.getenv("XDG_RUNTIME_DIR");
+               if (xdgRunDir != null) {
+                       // TODO support multiple names
+                       runDir = Paths.get(xdgRunDir);
+               } else {
+                       runDir = Paths.get(System.getProperty("user.home"), ".cache/argeo");
+               }
+               return runDir;
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/PasswordEncryption.java b/org.argeo.cms/src/org/argeo/cms/util/PasswordEncryption.java
new file mode 100644 (file)
index 0000000..c50f415
--- /dev/null
@@ -0,0 +1,216 @@
+package org.argeo.cms.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class PasswordEncryption {
+       public final static Integer DEFAULT_ITERATION_COUNT = 1024;
+       /** Stronger with 256, but causes problem with Oracle JVM */
+       public final static Integer DEFAULT_SECRETE_KEY_LENGTH = 256;
+       public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED = 128;
+       public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1";
+       public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES";
+       public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding";
+//     public final static String DEFAULT_CHARSET = "UTF-8";
+       public final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
+
+       private Integer iterationCount = DEFAULT_ITERATION_COUNT;
+       private Integer secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH;
+       private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY;
+       private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION;
+       private String cipherName = DEFAULT_CIPHER_NAME;
+
+       private static byte[] DEFAULT_SALT_8 = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
+                       (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
+       private static byte[] DEFAULT_IV_16 = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
+                       (byte) 0x35, (byte) 0xE3, (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
+                       (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
+
+       private Key key;
+       private Cipher ecipher;
+       private Cipher dcipher;
+
+       private String securityProviderName = null;
+
+       /**
+        * This is up to the caller to clear the passed array. Neither copy of nor
+        * reference to the passed array is kept
+        */
+       public PasswordEncryption(char[] password) {
+               this(password, DEFAULT_SALT_8, DEFAULT_IV_16);
+       }
+
+       /**
+        * This is up to the caller to clear the passed array. Neither copies of nor
+        * references to the passed arrays are kept
+        */
+       public PasswordEncryption(char[] password, byte[] passwordSalt, byte[] initializationVector) {
+               try {
+                       initKeyAndCiphers(password, passwordSalt, initializationVector);
+               } catch (InvalidKeyException e) {
+                       Integer previousSecreteKeyLength = secreteKeyLength;
+                       secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED;
+                       System.err.println("'" + e.getMessage() + "', will use " + secreteKeyLength
+                                       + " secrete key length instead of " + previousSecreteKeyLength);
+                       try {
+                               initKeyAndCiphers(password, passwordSalt, initializationVector);
+                       } catch (GeneralSecurityException e1) {
+                               throw new IllegalStateException("Cannot get secret key (with restricted length)", e1);
+                       }
+               } catch (GeneralSecurityException e) {
+                       throw new IllegalStateException("Cannot get secret key", e);
+               }
+       }
+
+       protected void initKeyAndCiphers(char[] password, byte[] passwordSalt, byte[] initializationVector)
+                       throws GeneralSecurityException {
+               byte[] salt = new byte[8];
+               System.arraycopy(passwordSalt, 0, salt, 0, salt.length);
+               // for (int i = 0; i < password.length && i < salt.length; i++)
+               // salt[i] = (byte) password[i];
+               byte[] iv = new byte[16];
+               System.arraycopy(initializationVector, 0, iv, 0, iv.length);
+
+               SecretKeyFactory keyFac = SecretKeyFactory.getInstance(getSecretKeyFactoryName());
+               PBEKeySpec keySpec = new PBEKeySpec(password, salt, getIterationCount(), getKeyLength());
+               String secKeyEncryption = getSecretKeyEncryption();
+               if (secKeyEncryption != null) {
+                       SecretKey tmp = keyFac.generateSecret(keySpec);
+                       key = new SecretKeySpec(tmp.getEncoded(), getSecretKeyEncryption());
+               } else {
+                       key = keyFac.generateSecret(keySpec);
+               }
+               if (securityProviderName != null)
+                       ecipher = Cipher.getInstance(getCipherName(), securityProviderName);
+               else
+                       ecipher = Cipher.getInstance(getCipherName());
+               ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
+               dcipher = Cipher.getInstance(getCipherName());
+               dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
+       }
+
+       public void encrypt(InputStream decryptedIn, OutputStream encryptedOut) throws IOException {
+               try {
+                       CipherOutputStream out = new CipherOutputStream(encryptedOut, ecipher);
+                       StreamUtils.copy(decryptedIn, out);
+                       StreamUtils.closeQuietly(out);
+               } catch (IOException e) {
+                       throw e;
+               } finally {
+                       StreamUtils.closeQuietly(decryptedIn);
+               }
+       }
+
+       public void decrypt(InputStream encryptedIn, OutputStream decryptedOut) throws IOException {
+               try {
+                       CipherInputStream decryptedIn = new CipherInputStream(encryptedIn, dcipher);
+                       StreamUtils.copy(decryptedIn, decryptedOut);
+               } catch (IOException e) {
+                       throw e;
+               } finally {
+                       StreamUtils.closeQuietly(encryptedIn);
+               }
+       }
+
+       public byte[] encryptString(String str) {
+               ByteArrayOutputStream out = null;
+               ByteArrayInputStream in = null;
+               try {
+                       out = new ByteArrayOutputStream();
+                       in = new ByteArrayInputStream(str.getBytes(DEFAULT_CHARSET));
+                       encrypt(in, out);
+                       return out.toByteArray();
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               } finally {
+                       StreamUtils.closeQuietly(out);
+               }
+       }
+
+       /** Closes the input stream */
+       public String decryptAsString(InputStream in) {
+               ByteArrayOutputStream out = null;
+               try {
+                       out = new ByteArrayOutputStream();
+                       decrypt(in, out);
+                       return new String(out.toByteArray(), DEFAULT_CHARSET);
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               } finally {
+                       StreamUtils.closeQuietly(out);
+               }
+       }
+
+       protected Key getKey() {
+               return key;
+       }
+
+       protected Cipher getEcipher() {
+               return ecipher;
+       }
+
+       protected Cipher getDcipher() {
+               return dcipher;
+       }
+
+       protected Integer getIterationCount() {
+               return iterationCount;
+       }
+
+       protected Integer getKeyLength() {
+               return secreteKeyLength;
+       }
+
+       protected String getSecretKeyFactoryName() {
+               return secreteKeyFactoryName;
+       }
+
+       protected String getSecretKeyEncryption() {
+               return secreteKeyEncryption;
+       }
+
+       protected String getCipherName() {
+               return cipherName;
+       }
+
+       public void setIterationCount(Integer iterationCount) {
+               this.iterationCount = iterationCount;
+       }
+
+       public void setSecreteKeyLength(Integer keyLength) {
+               this.secreteKeyLength = keyLength;
+       }
+
+       public void setSecreteKeyFactoryName(String secreteKeyFactoryName) {
+               this.secreteKeyFactoryName = secreteKeyFactoryName;
+       }
+
+       public void setSecreteKeyEncryption(String secreteKeyEncryption) {
+               this.secreteKeyEncryption = secreteKeyEncryption;
+       }
+
+       public void setCipherName(String cipherName) {
+               this.cipherName = cipherName;
+       }
+
+       public void setSecurityProviderName(String securityProviderName) {
+               this.securityProviderName = securityProviderName;
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/ServiceChannel.java b/org.argeo.cms/src/org/argeo/cms/util/ServiceChannel.java
new file mode 100644 (file)
index 0000000..8cdbcad
--- /dev/null
@@ -0,0 +1,78 @@
+package org.argeo.cms.util;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousByteChannel;
+import java.nio.channels.CompletionHandler;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+/** An {@link AsynchronousByteChannel} based on an {@link ExecutorService}. */
+public class ServiceChannel implements AsynchronousByteChannel {
+       private final ReadableByteChannel in;
+       private final WritableByteChannel out;
+
+       private boolean open = true;
+
+       private ExecutorService executor;
+
+       public ServiceChannel(ReadableByteChannel in, WritableByteChannel out, ExecutorService executor) {
+               this.in = in;
+               this.out = out;
+               this.executor = executor;
+       }
+
+       @Override
+       public Future<Integer> read(ByteBuffer dst) {
+               return executor.submit(() -> in.read(dst));
+       }
+
+       @Override
+       public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
+               try {
+                       Future<Integer> res = read(dst);
+                       handler.completed(res.get(), attachment);
+               } catch (Exception e) {
+                       handler.failed(e, attachment);
+               }
+       }
+
+       @Override
+       public Future<Integer> write(ByteBuffer src) {
+               return executor.submit(() -> out.write(src));
+       }
+
+       @Override
+       public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
+               try {
+                       Future<Integer> res = write(src);
+                       handler.completed(res.get(), attachment);
+               } catch (Exception e) {
+                       handler.failed(e, attachment);
+               }
+       }
+
+       @Override
+       public synchronized void close() throws IOException {
+               try {
+                       in.close();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               try {
+                       out.close();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               open = false;
+               notifyAll();
+       }
+
+       @Override
+       public synchronized boolean isOpen() {
+               return open;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/StreamUtils.java b/org.argeo.cms/src/org/argeo/cms/util/StreamUtils.java
new file mode 100644 (file)
index 0000000..a589e73
--- /dev/null
@@ -0,0 +1,98 @@
+package org.argeo.cms.util;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.StringJoiner;
+
+/** Stream utilities to be used when Apache Commons IO is not available. */
+public class StreamUtils {
+       private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+       /*
+        * APACHE COMMONS IO (inspired)
+        */
+
+       /** @return the number of bytes */
+       public static Long copy(InputStream in, OutputStream out) throws IOException {
+               Long count = 0l;
+               byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
+               while (true) {
+                       int length = in.read(buf);
+                       if (length < 0)
+                               break;
+                       out.write(buf, 0, length);
+                       count = count + length;
+               }
+               return count;
+       }
+
+       /** @return the number of chars */
+       public static Long copy(Reader in, Writer out) throws IOException {
+               Long count = 0l;
+               char[] buf = new char[DEFAULT_BUFFER_SIZE];
+               while (true) {
+                       int length = in.read(buf);
+                       if (length < 0)
+                               break;
+                       out.write(buf, 0, length);
+                       count = count + length;
+               }
+               return count;
+       }
+
+       public static byte[] toByteArray(InputStream in) throws IOException {
+               try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+                       copy(in, out);
+                       return out.toByteArray();
+               }
+       }
+
+       public static void closeQuietly(InputStream in) {
+               if (in != null)
+                       try {
+                               in.close();
+                       } catch (Exception e) {
+                               //
+                       }
+       }
+
+       public static void closeQuietly(OutputStream out) {
+               if (out != null)
+                       try {
+                               out.close();
+                       } catch (Exception e) {
+                               //
+                       }
+       }
+
+       public static void closeQuietly(Reader in) {
+               if (in != null)
+                       try {
+                               in.close();
+                       } catch (Exception e) {
+                               //
+                       }
+       }
+
+       public static void closeQuietly(Writer out) {
+               if (out != null)
+                       try {
+                               out.close();
+                       } catch (Exception e) {
+                               //
+                       }
+       }
+
+       public static String toString(BufferedReader reader) throws IOException {
+               StringJoiner sn = new StringJoiner("\n");
+               String line = null;
+               while ((line = reader.readLine()) != null)
+                       sn.add(line);
+               return sn.toString();
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/Tester.java b/org.argeo.cms/src/org/argeo/cms/util/Tester.java
new file mode 100644 (file)
index 0000000..fa62cd7
--- /dev/null
@@ -0,0 +1,126 @@
+package org.argeo.cms.util;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/** A generic tester based on Java assertions and functional programming. */
+public class Tester {
+       private Map<String, TesterStatus> results = Collections.synchronizedSortedMap(new TreeMap<>());
+
+       private ClassLoader classLoader;
+
+       /** Use {@link Thread#getContextClassLoader()} by default. */
+       public Tester() {
+               this(Thread.currentThread().getContextClassLoader());
+       }
+
+       public Tester(ClassLoader classLoader) {
+               this.classLoader = classLoader;
+       }
+
+       public void execute(String className) {
+               Class<?> clss;
+               try {
+                       clss = classLoader.loadClass(className);
+                       boolean assertionsEnabled = clss.desiredAssertionStatus();
+                       if (!assertionsEnabled)
+                               throw new IllegalStateException("Test runner " + getClass().getName()
+                                               + " requires Java assertions to be enabled. Call the JVM with the -ea argument.");
+               } catch (Exception e1) {
+                       throw new IllegalArgumentException("Cannot initalise test for " + className, e1);
+
+               }
+               List<Method> methods = findMethods(clss);
+               if (methods.size() == 0)
+                       throw new IllegalArgumentException("No test method found in " + clss);
+               // TODO make order more predictable?
+               for (Method method : methods) {
+                       String uid = method.getDeclaringClass().getName() + "#" + method.getName();
+                       TesterStatus testStatus = new TesterStatus(uid);
+                       Object obj = null;
+                       try {
+                               beforeTest(uid, method);
+                               obj = clss.getDeclaredConstructor().newInstance();
+                               method.invoke(obj);
+                               testStatus.setPassed();
+                               afterTestPassed(uid, method, obj);
+                       } catch (Exception e) {
+                               testStatus.setFailed(e);
+                               afterTestFailed(uid, method, obj, e);
+                       } finally {
+                               results.put(uid, testStatus);
+                       }
+               }
+       }
+
+       protected void beforeTest(String uid, Method method) {
+               // System.out.println(uid + ": STARTING");
+       }
+
+       protected void afterTestPassed(String uid, Method method, Object obj) {
+               System.out.println(uid + ": PASSED");
+       }
+
+       protected void afterTestFailed(String uid, Method method, Object obj, Throwable e) {
+               System.out.println(uid + ": FAILED");
+               e.printStackTrace();
+       }
+
+       protected List<Method> findMethods(Class<?> clss) {
+               List<Method> methods = new ArrayList<Method>();
+//             Method call = getMethod(clss, "call");
+//             if (call != null)
+//                     methods.add(call);
+//
+               for (Method method : clss.getMethods()) {
+                       if (method.getName().startsWith("test")) {
+                               methods.add(method);
+                       }
+               }
+               return methods;
+       }
+
+       protected Method getMethod(Class<?> clss, String name, Class<?>... parameterTypes) {
+               try {
+                       return clss.getMethod(name, parameterTypes);
+               } catch (NoSuchMethodException e) {
+                       return null;
+               } catch (SecurityException e) {
+                       throw new IllegalStateException(e);
+               }
+       }
+
+       public static void main(String[] args) {
+               // deal with arguments
+               String className;
+               if (args.length < 1) {
+                       System.err.println(usage());
+                       System.exit(1);
+                       throw new IllegalArgumentException();
+               } else {
+                       className = args[0];
+               }
+
+               Tester test = new Tester();
+               try {
+                       test.execute(className);
+               } catch (Throwable e) {
+                       e.printStackTrace();
+               }
+
+               Map<String, TesterStatus> r = test.results;
+               for (String uid : r.keySet()) {
+                       TesterStatus testStatus = r.get(uid);
+                       System.out.println(testStatus);
+               }
+       }
+
+       public static String usage() {
+               return "java " + Tester.class.getName() + " [test class name]";
+
+       }
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/TesterStatus.java b/org.argeo.cms/src/org/argeo/cms/util/TesterStatus.java
new file mode 100644 (file)
index 0000000..09ab432
--- /dev/null
@@ -0,0 +1,98 @@
+package org.argeo.cms.util;
+
+import java.io.Serializable;
+
+/** The status of a test. */
+public class TesterStatus implements Serializable {
+       private static final long serialVersionUID = 6272975746885487000L;
+
+       private Boolean passed = null;
+       private final String uid;
+       private Throwable throwable = null;
+
+       public TesterStatus(String uid) {
+               this.uid = uid;
+       }
+
+       /** For cloning. */
+       public TesterStatus(String uid, Boolean passed, Throwable throwable) {
+               this(uid);
+               this.passed = passed;
+               this.throwable = throwable;
+       }
+
+       public synchronized Boolean isRunning() {
+               return passed == null;
+       }
+
+       public synchronized Boolean isPassed() {
+               assert passed != null;
+               return passed;
+       }
+
+       public synchronized Boolean isFailed() {
+               assert passed != null;
+               return !passed;
+       }
+
+       public synchronized void setPassed() {
+               setStatus(true);
+       }
+
+       public synchronized void setFailed() {
+               setStatus(false);
+       }
+
+       public synchronized void setFailed(Throwable throwable) {
+               setStatus(false);
+               setThrowable(throwable);
+       }
+
+       protected void setStatus(Boolean passed) {
+               if (this.passed != null)
+                       throw new IllegalStateException("Passed status of test " + uid + " is already set (to " + passed + ")");
+               this.passed = passed;
+       }
+
+       protected void setThrowable(Throwable throwable) {
+               if (this.throwable != null)
+                       throw new IllegalStateException("Throwable of test " + uid + " is already set (to " + passed + ")");
+               this.throwable = throwable;
+       }
+
+       public String getUid() {
+               return uid;
+       }
+
+       public Throwable getThrowable() {
+               return throwable;
+       }
+
+       @Override
+       protected Object clone() throws CloneNotSupportedException {
+               // TODO Auto-generated method stub
+               return super.clone();
+       }
+
+       @Override
+       public boolean equals(Object o) {
+               if (o instanceof TesterStatus) {
+                       TesterStatus other = (TesterStatus) o;
+                       // we don't check consistency for performance purposes
+                       // this equals() is supposed to be used in collections or for transfer
+                       return other.uid.equals(uid);
+               }
+               return false;
+       }
+
+       @Override
+       public int hashCode() {
+               return uid.hashCode();
+       }
+
+       @Override
+       public String toString() {
+               return uid + "\t" + (passed ? "passed" : "failed");
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/Throughput.java b/org.argeo.cms/src/org/argeo/cms/util/Throughput.java
new file mode 100644 (file)
index 0000000..4fc15f9
--- /dev/null
@@ -0,0 +1,82 @@
+package org.argeo.cms.util;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
+/** A throughput, that is, a value per unit of time. */
+public class Throughput {
+       private final static NumberFormat usNumberFormat = NumberFormat.getInstance(Locale.US);
+
+       public enum Unit {
+               s, m, h, d
+       }
+
+       private final Double value;
+       private final Unit unit;
+
+       public Throughput(Double value, Unit unit) {
+               this.value = value;
+               this.unit = unit;
+       }
+
+       public Throughput(Long periodMs, Long count, Unit unit) {
+               if (unit.equals(Unit.s))
+                       value = ((double) count * 1000d) / periodMs;
+               else if (unit.equals(Unit.m))
+                       value = ((double) count * 60d * 1000d) / periodMs;
+               else if (unit.equals(Unit.h))
+                       value = ((double) count * 60d * 60d * 1000d) / periodMs;
+               else if (unit.equals(Unit.d))
+                       value = ((double) count * 24d * 60d * 60d * 1000d) / periodMs;
+               else
+                       throw new IllegalArgumentException("Unsupported unit " + unit);
+               this.unit = unit;
+       }
+
+       public Throughput(Double value, String unitStr) {
+               this(value, Unit.valueOf(unitStr));
+       }
+
+       public Throughput(String def) {
+               int index = def.indexOf('/');
+               if (def.length() < 3 || index <= 0 || index != def.length() - 2)
+                       throw new IllegalArgumentException(
+                                       def + " no a proper throughput definition" + " (should be <value>/<unit>, e.g. 3.54/s or 1500/h");
+               String valueStr = def.substring(0, index);
+               String unitStr = def.substring(index + 1);
+               try {
+                       this.value = usNumberFormat.parse(valueStr).doubleValue();
+               } catch (ParseException e) {
+                       throw new IllegalArgumentException("Cannot parse " + valueStr + " as a number.", e);
+               }
+               this.unit = Unit.valueOf(unitStr);
+       }
+
+       public Long asMsPeriod() {
+               if (unit.equals(Unit.s))
+                       return Math.round(1000d / value);
+               else if (unit.equals(Unit.m))
+                       return Math.round((60d * 1000d) / value);
+               else if (unit.equals(Unit.h))
+                       return Math.round((60d * 60d * 1000d) / value);
+               else if (unit.equals(Unit.d))
+                       return Math.round((24d * 60d * 60d * 1000d) / value);
+               else
+                       throw new IllegalArgumentException("Unsupported unit " + unit);
+       }
+
+       @Override
+       public String toString() {
+               return usNumberFormat.format(value) + '/' + unit;
+       }
+
+       public Double getValue() {
+               return value;
+       }
+
+       public Unit getUnit() {
+               return unit;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/util/package-info.java b/org.argeo.cms/src/org/argeo/cms/util/package-info.java
new file mode 100644 (file)
index 0000000..5efc68a
--- /dev/null
@@ -0,0 +1,2 @@
+/** Generic Java utilities. */
+package org.argeo.cms.util;
\ No newline at end of file
index aa9494c91591605e41f2061a8864d158cdc48d51..cab85d02ff3e8eefa19317916ebf0de3f286af30 100644 (file)
@@ -40,7 +40,7 @@ public class Service {
                                }
                        } catch (Exception e) {
                                e.printStackTrace();
-                               System.exit(1);
+                               Runtime.getRuntime().halt(1);
                        }
                }, "Runtime shutdown"));
 
index c28df3b238bf4a7acc85e4198fc93d55271e9356..5c8329c85e8616329a2154047273ac4b4ed943dd 100644 (file)
@@ -4,8 +4,15 @@ import java.net.URI;
 
 /** A provisioning source in A2 format. */
 public interface A2Source extends ProvisioningSource {
+       /** Use standard a2 protocol, installing from source URL. */
        final static String SCHEME_A2 = "a2";
+       /**
+        * Use equinox-specific reference: installation, which does not copy the bundle
+        * content.
+        */
+       final static String SCHEME_A2_REFERENCE = "a2+reference";
        final static String DEFAULT_A2_URI = SCHEME_A2 + ":///";
+       final static String DEFAULT_A2_REFERENCE_URI = SCHEME_A2_REFERENCE + ":///";
 
        URI getUri();
 }
index 0c3cefd014a915f7a02d0c5b8caf69c858a0b6e1..617e7887806f451a9eb89cd874610ccf8bab0344 100644 (file)
@@ -28,6 +28,12 @@ import org.osgi.framework.Version;
 public abstract class AbstractProvisioningSource implements ProvisioningSource {
        protected final Map<String, A2Contribution> contributions = Collections.synchronizedSortedMap(new TreeMap<>());
 
+       private final boolean usingReference;
+
+       public AbstractProvisioningSource(boolean usingReference) {
+               this.usingReference = usingReference;
+       }
+
        public Iterable<A2Contribution> listContributions(Object filter) {
                return contributions.values();
        }
@@ -35,16 +41,25 @@ public abstract class AbstractProvisioningSource implements ProvisioningSource {
        @Override
        public Bundle install(BundleContext bc, A2Module module) {
                try {
-                       Path tempJar = null;
-                       if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
-                               tempJar = toTempJar((Path) module.getLocator());
-                       Bundle bundle;
-                       try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
-                               bundle = bc.installBundle(module.getBranch().getCoordinates(), in);
+                       Object locator = module.getLocator();
+                       if (usingReference && locator instanceof Path locatorPath) {
+                               String referenceUrl = "reference:file:" + locatorPath.toString();
+                               Bundle bundle = bc.installBundle(referenceUrl);
+                               return bundle;
+                       } else {
+
+                               Path tempJar = null;
+                               if (locator instanceof Path && Files.isDirectory((Path) locator))
+                                       tempJar = toTempJar((Path) locator);
+                               Bundle bundle;
+                               try (InputStream in = newInputStream(tempJar != null ? tempJar : locator)) {
+                                       bundle = bc.installBundle(module.getBranch().getCoordinates(), in);
+                               }
+
+                               if (tempJar != null)
+                                       Files.deleteIfExists(tempJar);
+                               return bundle;
                        }
-                       if (tempJar != null)
-                               Files.deleteIfExists(tempJar);
-                       return bundle;
                } catch (BundleException | IOException e) {
                        throw new A2Exception("Cannot install module " + module, e);
                }
@@ -53,14 +68,21 @@ public abstract class AbstractProvisioningSource implements ProvisioningSource {
        @Override
        public void update(Bundle bundle, A2Module module) {
                try {
-                       Path tempJar = null;
-                       if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
-                               tempJar = toTempJar((Path) module.getLocator());
-                       try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
-                               bundle.update(in);
+                       Object locator = module.getLocator();
+                       if (usingReference && locator instanceof Path) {
+                               try (InputStream in = newInputStream(locator)) {
+                                       bundle.update(in);
+                               }
+                       } else {
+                               Path tempJar = null;
+                               if (locator instanceof Path && Files.isDirectory((Path) locator))
+                                       tempJar = toTempJar((Path) locator);
+                               try (InputStream in = newInputStream(tempJar != null ? tempJar : locator)) {
+                                       bundle.update(in);
+                               }
+                               if (tempJar != null)
+                                       Files.deleteIfExists(tempJar);
                        }
-                       if (tempJar != null)
-                               Files.deleteIfExists(tempJar);
                } catch (BundleException | IOException e) {
                        throw new A2Exception("Cannot update module " + module, e);
                }
@@ -174,6 +196,20 @@ public abstract class AbstractProvisioningSource implements ProvisioningSource {
                return symbolicName;
        }
 
+       protected boolean isUsingReference() {
+               return usingReference;
+       }
+
+       private InputStream newInputStream(Object locator) throws IOException {
+               if (locator instanceof Path) {
+                       return Files.newInputStream((Path) locator);
+               } else if (locator instanceof URL) {
+                       return ((URL) locator).openStream();
+               } else {
+                       throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass());
+               }
+       }
+
        private static Manifest findManifest(Path currentPath) {
                Path metaInfPath = currentPath.resolve("META-INF");
                if (Files.exists(metaInfPath) && Files.isDirectory(metaInfPath)) {
@@ -219,13 +255,4 @@ public abstract class AbstractProvisioningSource implements ProvisioningSource {
 
        }
 
-       private InputStream newInputStream(Object locator) throws IOException {
-               if (locator instanceof Path) {
-                       return Files.newInputStream((Path) locator);
-               } else if (locator instanceof URL) {
-                       return ((URL) locator).openStream();
-               } else {
-                       throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass());
-               }
-       }
 }
index 8a9e5e67f1f323bb2755a16e5f11a0726c64fc1b..12de4228ba9a57e55eb3c43a180bb1810db349e4 100644 (file)
@@ -11,10 +11,15 @@ import org.argeo.init.osgi.OsgiBootUtils;
 import org.osgi.framework.Version;
 
 /**
- * A provisioning source based on the linear classpath with which the JCM has
+ * A provisioning source based on the linear classpath with which the JVM has
  * been started.
  */
 public class ClasspathSource extends AbstractProvisioningSource {
+       
+       public ClasspathSource() {
+               super(true);
+       }
+
        void load() throws IOException {
                A2Contribution classpathContribution = getOrAddContribution( A2Contribution.CLASSPATH);
                List<String> classpath = Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator));
index 5099eed15be9509ec516a44223dc095b07114025..e0e2e437f58307c50b60e53500634b3111da2f21 100644 (file)
@@ -6,10 +6,10 @@ import java.net.URISyntaxException;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.SortedMap;
+import java.util.StringJoiner;
 import java.util.TreeMap;
 
 import org.argeo.init.osgi.OsgiBootUtils;
@@ -18,15 +18,16 @@ import org.osgi.framework.Version;
 /** A file system {@link AbstractProvisioningSource} in A2 format. */
 public class FsA2Source extends AbstractProvisioningSource implements A2Source {
        private final Path base;
-       private Map<String, String> xOr;
+       private final Map<String, String> variantsXOr;
 
-       public FsA2Source(Path base) {
-               this(base, new HashMap<>());
-       }
+//     public FsA2Source(Path base) {
+//             this(base, new HashMap<>());
+//     }
 
-       public FsA2Source(Path base, Map<String, String> xOr) {
+       public FsA2Source(Path base, Map<String, String> variantsXOr, boolean usingReference) {
+               super(usingReference);
                this.base = base;
-               this.xOr = xOr;
+               this.variantsXOr = new HashMap<>(variantsXOr);
        }
 
        void load() throws IOException {
@@ -44,7 +45,7 @@ public class FsA2Source extends AbstractProvisioningSource implements A2Source {
                                } else {// variants
                                        Path variantPath = null;
                                        // is it an explicit variant?
-                                       String variant = xOr.get(contributionPath.getFileName().toString());
+                                       String variant = variantsXOr.get(contributionPath.getFileName().toString());
                                        if (variant != null) {
                                                variantPath = contributionPath.resolve(variant);
                                        }
@@ -92,19 +93,8 @@ public class FsA2Source extends AbstractProvisioningSource implements A2Source {
                                        String ext = moduleFileName.substring(lastDot + 1);
                                        if (!"jar".equals(ext))
                                                continue modules;
-//                                     String moduleName = moduleFileName.substring(0, lastDot);
-//                                     if (moduleName.endsWith("-SNAPSHOT"))
-//                                             moduleName = moduleName.substring(0, moduleName.length() - "-SNAPSHOT".length());
-//                                     int lastDash = moduleName.lastIndexOf('-');
-//                                     String versionStr = moduleName.substring(lastDash + 1);
-//                                     String componentName = moduleName.substring(0, lastDash);
-                                       // if(versionStr.endsWith("-SNAPSHOT")) {
-                                       // versionStr = readVersionFromModule(modulePath);
-                                       // }
                                        Version version;
-//                                     try {
-//                                             version = new Version(versionStr);
-//                                     } catch (Exception e) {
+                                       // TODO optimise? check attributes?
                                        String[] nameVersion = readNameVersionFromModule(modulePath);
                                        String componentName = nameVersion[0];
                                        String versionStr = nameVersion[1];
@@ -130,7 +120,16 @@ public class FsA2Source extends AbstractProvisioningSource implements A2Source {
                URI baseUri = base.toUri();
                try {
                        if (baseUri.getScheme().equals("file")) {
-                               return new URI(SCHEME_A2, null, base.toString(), null);
+                               String queryPart = "";
+                               if (!getVariantsXOr().isEmpty()) {
+                                       StringJoiner sj = new StringJoiner("&");
+                                       for (String key : getVariantsXOr().keySet()) {
+                                               sj.add(key + "=" + getVariantsXOr().get(key));
+                                       }
+                                       queryPart = sj.toString();
+                               }
+                               return new URI(isUsingReference() ? SCHEME_A2_REFERENCE : SCHEME_A2, null, base.toString(), queryPart,
+                                               null);
                        } else {
                                throw new UnsupportedOperationException("Unsupported scheme " + baseUri.getScheme());
                        }
@@ -139,19 +138,23 @@ public class FsA2Source extends AbstractProvisioningSource implements A2Source {
                }
        }
 
-       public static void main(String[] args) {
-               if (args.length == 0)
-                       throw new IllegalArgumentException("Usage: <path to A2 base>");
-               try {
-                       Map<String, String> xOr = new HashMap<>();
-                       xOr.put("osgi", "equinox");
-                       xOr.put("swt", "rap");
-                       FsA2Source context = new FsA2Source(Paths.get(args[0]), xOr);
-                       context.load();
-                       context.asTree();
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
+       protected Map<String, String> getVariantsXOr() {
+               return variantsXOr;
        }
 
+//     public static void main(String[] args) {
+//             if (args.length == 0)
+//                     throw new IllegalArgumentException("Usage: <path to A2 base>");
+//             try {
+//                     Map<String, String> xOr = new HashMap<>();
+//                     xOr.put("osgi", "equinox");
+//                     xOr.put("swt", "rap");
+//                     FsA2Source context = new FsA2Source(Paths.get(args[0]), xOr);
+//                     context.load();
+//                     context.asTree();
+//             } catch (Exception e) {
+//                     e.printStackTrace();
+//             }
+//     }
+
 }
index 1657fad57e9835784f9a39890ea9b8558e732821..0313d20f367ed32d2fa44a24f213f3decb76daa9 100644 (file)
@@ -17,7 +17,7 @@ public class FsM2Source extends AbstractProvisioningSource {
        private final Path base;
 
        public FsM2Source(Path base) {
-               super();
+               super(false);
                this.base = base;
        }
 
index 35fbee3568a4b3ea39d0709423ab4d33d31c1499..0064ab9eddbb1c4d3c8c37148eb9efaaa68f61aa 100644 (file)
@@ -11,11 +11,12 @@ class OsgiContext extends AbstractProvisioningSource {
        private final BundleContext bc;
 
        public OsgiContext(BundleContext bc) {
-               super();
+               super(false);
                this.bc = bc;
        }
 
        public OsgiContext() {
+               super(false);
                Bundle bundle = FrameworkUtil.getBundle(OsgiContext.class);
                if (bundle == null)
                        throw new IllegalArgumentException(
index 6d842650c2620fd2d26249bf69d7d741a37aa3fd..cbb296f4c1b780240ddd610ac3257fd8d8218476 100644 (file)
@@ -1,5 +1,8 @@
 package org.argeo.init.a2;
 
+import static org.argeo.init.a2.A2Source.SCHEME_A2;
+import static org.argeo.init.a2.A2Source.SCHEME_A2_REFERENCE;
+
 import java.io.File;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
@@ -9,7 +12,6 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -25,7 +27,6 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
-import org.osgi.framework.launch.Framework;
 import org.osgi.framework.wiring.FrameworkWiring;
 
 /** Loads provisioning sources into an OSGi context. */
@@ -54,8 +55,8 @@ public class ProvisioningManager {
                                        updatedBundles.add(bundle);
                        }
                }
-               FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
-               frameworkWiring.refreshBundles(updatedBundles);
+//             FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
+//             frameworkWiring.refreshBundles(updatedBundles);
        }
 
        public void registerSource(String uri) {
@@ -72,7 +73,7 @@ public class ProvisioningManager {
                                xOr.put(key, lst.get(0));
                        }
 
-                       if (A2Source.SCHEME_A2.equals(u.getScheme())) {
+                       if (SCHEME_A2.equals(u.getScheme()) || SCHEME_A2_REFERENCE.equals(u.getScheme())) {
                                if (u.getHost() == null || "".equals(u.getHost())) {
                                        String baseStr = u.getPath();
                                        if (File.separatorChar == '\\') {// MS Windows
@@ -80,12 +81,19 @@ public class ProvisioningManager {
                                        }
                                        Path base = Paths.get(baseStr);
                                        if (Files.exists(base)) {
-                                               FsA2Source source = new FsA2Source(base, xOr);
+                                               FsA2Source source = new FsA2Source(base, xOr, SCHEME_A2_REFERENCE.equals(u.getScheme()));
                                                source.load();
                                                addSource(source);
                                                OsgiBootUtils.info("Registered " + uri + " as source");
+                                       } else {
+                                               OsgiBootUtils.debug("Source " + base + " does not exist, ignoring.");
                                        }
+                               } else {
+                                       throw new UnsupportedOperationException(
+                                                       "Remote installation is not yet supported, cannot add source " + u);
                                }
+                       } else {
+                               throw new IllegalArgumentException("Unkown scheme: for source " + u);
                        }
                } catch (Exception e) {
                        throw new A2Exception("Cannot add source " + uri, e);
@@ -217,46 +225,46 @@ public class ProvisioningManager {
                }
        }
 
-       public static void main(String[] args) {
-               if (args.length == 0)
-                       throw new IllegalArgumentException("Usage: <path to A2 base>");
-               Map<String, String> configuration = new HashMap<>();
-               configuration.put("osgi.console", "2323");
-               configuration.put("org.osgi.framework.bootdelegation",
-                               "com.sun.jndi.ldap,com.sun.jndi.ldap.sasl,com.sun.security.jgss,com.sun.jndi.dns,com.sun.nio.file,com.sun.nio.sctp,sun.nio.cs");
-               Framework framework = OsgiBootUtils.launch(configuration);
-               try {
-                       ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
-                       Map<String, String> xOr = new HashMap<>();
-                       xOr.put("osgi", "equinox");
-                       xOr.put("swt", "rap");
-                       FsA2Source context = new FsA2Source(Paths.get(args[0]), xOr);
-                       context.load();
-                       pm.addSource(context);
-                       if (framework.getBundleContext().getBundles().length == 1) {// initial
-                               pm.install(null);
-                       } else {
-                               pm.update();
-                       }
-
-                       Thread.sleep(2000);
-
-                       Bundle[] bundles = framework.getBundleContext().getBundles();
-                       Arrays.sort(bundles, (b1, b2) -> b1.getSymbolicName().compareTo(b2.getSymbolicName()));
-                       for (Bundle b : bundles)
-                               if (b.getState() == Bundle.RESOLVED || b.getState() == Bundle.STARTING || b.getState() == Bundle.ACTIVE)
-                                       System.out.println(b.getSymbolicName() + " " + b.getVersion());
-                               else
-                                       System.err.println(b.getSymbolicName() + " " + b.getVersion() + " (" + b.getState() + ")");
-               } catch (Exception e) {
-                       e.printStackTrace();
-               } finally {
-                       try {
-                               framework.stop();
-                       } catch (Exception e) {
-                               e.printStackTrace();
-                       }
-               }
-       }
+//     public static void main(String[] args) {
+//             if (args.length == 0)
+//                     throw new IllegalArgumentException("Usage: <path to A2 base>");
+//             Map<String, String> configuration = new HashMap<>();
+//             configuration.put("osgi.console", "2323");
+//             configuration.put("org.osgi.framework.bootdelegation",
+//                             "com.sun.jndi.ldap,com.sun.jndi.ldap.sasl,com.sun.security.jgss,com.sun.jndi.dns,com.sun.nio.file,com.sun.nio.sctp,sun.nio.cs");
+//             Framework framework = OsgiBootUtils.launch(configuration);
+//             try {
+//                     ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
+//                     Map<String, String> xOr = new HashMap<>();
+//                     xOr.put("osgi", "equinox");
+//                     xOr.put("swt", "rap");
+//                     FsA2Source context = new FsA2Source(Paths.get(args[0]), xOr);
+//                     context.load();
+//                     pm.addSource(context);
+//                     if (framework.getBundleContext().getBundles().length == 1) {// initial
+//                             pm.install(null);
+//                     } else {
+//                             pm.update();
+//                     }
+//
+//                     Thread.sleep(2000);
+//
+//                     Bundle[] bundles = framework.getBundleContext().getBundles();
+//                     Arrays.sort(bundles, (b1, b2) -> b1.getSymbolicName().compareTo(b2.getSymbolicName()));
+//                     for (Bundle b : bundles)
+//                             if (b.getState() == Bundle.RESOLVED || b.getState() == Bundle.STARTING || b.getState() == Bundle.ACTIVE)
+//                                     System.out.println(b.getSymbolicName() + " " + b.getVersion());
+//                             else
+//                                     System.err.println(b.getSymbolicName() + " " + b.getVersion() + " (" + b.getState() + ")");
+//             } catch (Exception e) {
+//                     e.printStackTrace();
+//             } finally {
+//                     try {
+//                             framework.stop();
+//                     } catch (Exception e) {
+//                             e.printStackTrace();
+//                     }
+//             }
+//     }
 
 }
index 003718785b82e37e13b9f203b51151193aca350b..884461b12b5b0e5bb322ddd96705c619af6a0f1f 100644 (file)
@@ -104,6 +104,13 @@ public class OsgiBoot implements OsgiBootConstants {
                                                                A2Source.SCHEME_A2 + "://" + homePath.toString() + "/.local/share/a2" + queryPart);
                                        provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/local/share/a2" + queryPart);
                                        provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/share/a2" + queryPart);
+                               } else if (source.trim().equals(A2Source.DEFAULT_A2_REFERENCE_URI)) {
+                                       if (Files.exists(homePath))
+                                               provisioningManager.registerSource(A2Source.SCHEME_A2_REFERENCE + "://" + homePath.toString()
+                                                               + "/.local/share/a2" + queryPart);
+                                       provisioningManager
+                                                       .registerSource(A2Source.SCHEME_A2_REFERENCE + ":///usr/local/share/a2" + queryPart);
+                                       provisioningManager.registerSource(A2Source.SCHEME_A2_REFERENCE + ":///usr/share/a2" + queryPart);
                                } else {
                                        provisioningManager.registerSource(source + queryPart);
                                }
@@ -126,36 +133,6 @@ public class OsgiBoot implements OsgiBootConstants {
        public void bootstrap(Map<String, String> properties) {
                try {
                        long begin = System.currentTimeMillis();
-                       // check properties
-//                     if (properties != null) {
-//                             for (String property : properties.keySet()) {
-//                                     String value = properties.get(property);
-//                                     String bcValue = bundleContext.getProperty(property);
-//                                     if (PROP_OSGI_CONFIGURATION_AREA.equals(property) || PROP_OSGI_INSTANCE_AREA.equals(property)) {
-//                                             try {
-//                                                     if (value.startsWith("/"))
-//                                                             value = "file://" + value;
-//                                                     URL uri = new URL(value);
-//                                                     URL bcUri = new URL(bcValue);
-//                                                     if (!uri.equals(bcUri))
-//                                                             throw new IllegalArgumentException("Property " + property + "=" + uri
-//                                                                             + " is inconsistent with bundle context : " + bcUri);
-//                                             } catch (MalformedURLException e) {
-//                                                     throw new IllegalArgumentException("Malformed property " + property, e);
-//                                             }
-//
-//                                     } else {
-//                                             if (!value.equals(bcValue))
-//                                                     throw new IllegalArgumentException("Property " + property + "=" + value
-//                                                                     + " is inconsistent with bundle context : " + bcValue);
-//                                     }
-//                             }
-//                     } else {
-//                             String useSystemProperties = bundleContext.getProperty(PROP_OSGI_USE_SYSTEM_PROPERTIES);
-//                             if (useSystemProperties == null || !useSystemProperties.equals("true")) {
-//                                     OsgiBootUtils.warn("No properties passed but " + PROP_OSGI_USE_SYSTEM_PROPERTIES + " is not set.");
-//                             }
-//                     }
 
                        // notify start
                        String osgiInstancePath = getProperty(PROP_OSGI_INSTANCE_AREA);
@@ -174,6 +151,9 @@ public class OsgiBoot implements OsgiBootConstants {
                        // A2 install bundles
                        provisioningManager.install(null);
 
+                       // Make sure fragments are properly considered by refreshing
+                       refreshFramework();
+
                        // start bundles
 //                     if (properties != null && !Boolean.parseBoolean(properties.get(PROP_OSGI_USE_SYSTEM_PROPERTIES)))
                        startBundles(properties);
@@ -242,7 +222,7 @@ public class OsgiBoot implements OsgiBootConstants {
                        String url = (String) urls.get(i);
                        installUrl(url, installedBundles);
                }
-               refreshFramework();
+//             refreshFramework();
        }
 
        /** Actually install the provided URL */
@@ -319,15 +299,6 @@ public class OsgiBoot implements OsgiBootConstants {
        /*
         * START
         */
-//     /**
-//      * Start bundles based on system properties.
-//      * 
-//      * @see OsgiBoot#doStartBundles(Map)
-//      */
-//     public void startBundles() {
-//             Properties properties = System.getProperties();
-//             startBundles(properties);
-//     }
 
        /**
         * Start bundles based on these properties.
@@ -384,8 +355,17 @@ public class OsgiBoot implements OsgiBootConstants {
                FrameworkStartLevel frameworkStartLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class);
 
                // default and active start levels from System properties
-               Integer defaultStartLevel = Integer.parseInt(getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4"));
-               Integer activeStartLevel = Integer.parseInt(getProperty(PROP_OSGI_STARTLEVEL, "6"));
+               int initialStartLevel = frameworkStartLevel.getInitialBundleStartLevel();
+               int defaultStartLevel = Integer.parseInt(getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4"));
+               int activeStartLevel = Integer.parseInt(getProperty(PROP_OSGI_STARTLEVEL, "6"));
+               if (OsgiBootUtils.isDebug()) {
+                       OsgiBootUtils.debug("OSGi default start level: "
+                                       + getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "<not set>") + ", using " + defaultStartLevel);
+                       OsgiBootUtils.debug("OSGi active start level: " + getProperty(PROP_OSGI_STARTLEVEL, "<not set>")
+                                       + ", using " + activeStartLevel);
+                       OsgiBootUtils.debug("Framework start level: " + frameworkStartLevel.getStartLevel() + " (initial: "
+                                       + initialStartLevel + ")");
+               }
 
                SortedMap<Integer, List<String>> startLevels = new TreeMap<Integer, List<String>>();
                computeStartLevels(startLevels, properties, defaultStartLevel);
@@ -412,13 +392,40 @@ public class OsgiBoot implements OsgiBootConstants {
                                }
                        }
                }
+
+               if (OsgiBootUtils.isDebug())
+                       OsgiBootUtils.debug("About to set framework start level to " + activeStartLevel + " ...");
+
                frameworkStartLevel.setStartLevel(activeStartLevel, (FrameworkEvent event) -> {
-                       if (OsgiBootUtils.isDebug())
-                               OsgiBootUtils.debug("Framework event: " + event);
-                       int initialStartLevel = frameworkStartLevel.getInitialBundleStartLevel();
-                       int startLevel = frameworkStartLevel.getStartLevel();
-                       OsgiBootUtils.debug("Framework start level: " + startLevel + " (initial: " + initialStartLevel + ")");
+                       if (event.getType() == FrameworkEvent.ERROR) {
+                               OsgiBootUtils.error("Start sequence failed", event.getThrowable());
+                       } else {
+                               if (OsgiBootUtils.isDebug())
+                                       OsgiBootUtils.debug("Framework started at level " + frameworkStartLevel.getStartLevel());
+                       }
                });
+
+//             // Start the framework level after level
+//             int currentStartLevel = frameworkStartLevel.getStartLevel();
+//             stages: for (int stage = currentStartLevel + 1; stage <= activeStartLevel; stage++) {
+//                     if (OsgiBootUtils.isDebug())
+//                             OsgiBootUtils.debug("Starting stage " + stage + "...");
+//                     final int nextStage = stage;
+//                     final CompletableFuture<FrameworkEvent> stageCompleted = new CompletableFuture<>();
+//                     frameworkStartLevel.setStartLevel(nextStage, (FrameworkEvent event) -> {
+//                             stageCompleted.complete(event);
+//                     });
+//                     FrameworkEvent event;
+//                     try {
+//                             event = stageCompleted.get();
+//                     } catch (InterruptedException | ExecutionException e) {
+//                             throw new IllegalStateException("Cannot continue start", e);
+//                     }
+//                     if (event.getThrowable() != null) {
+//                             OsgiBootUtils.error("Stage " + nextStage + " failed, aborting start.", event.getThrowable());
+//                             break stages;
+//                     }
+//             }
        }
 
        private static void computeStartLevels(SortedMap<Integer, List<String>> startLevels, Map<String, String> properties,
@@ -468,109 +475,6 @@ public class OsgiBoot implements OsgiBootConstants {
                }
        }
 
-//     /**
-//      * Start the provided list of bundles
-//      *
-//      * @return whether all bundles are now in active state
-//      * @deprecated
-//      */
-//     @Deprecated
-//     public boolean startBundles(List<String> bundlesToStart) {
-//             if (bundlesToStart.size() == 0)
-//                     return true;
-//
-//             // used to monitor ACTIVE states
-//             List<Bundle> startedBundles = new ArrayList<Bundle>();
-//             // used to log the bundles not found
-//             List<String> notFoundBundles = new ArrayList<String>(bundlesToStart);
-//
-//             Bundle[] bundles = bundleContext.getBundles();
-//             long startBegin = System.currentTimeMillis();
-//             for (int i = 0; i < bundles.length; i++) {
-//                     Bundle bundle = bundles[i];
-//                     String symbolicName = bundle.getSymbolicName();
-//                     if (bundlesToStart.contains(symbolicName))
-//                             try {
-//                                     try {
-//                                             bundle.start();
-//                                             if (OsgiBootUtils.isDebug())
-//                                                     debug("Bundle " + symbolicName + " started");
-//                                     } catch (Exception e) {
-//                                             OsgiBootUtils.warn("Start of bundle " + symbolicName + " failed because of " + e
-//                                                             + ", maybe bundle is not yet resolved," + " waiting and trying again.");
-//                                             waitForBundleResolvedOrActive(startBegin, bundle);
-//                                             bundle.start();
-//                                             startedBundles.add(bundle);
-//                                     }
-//                                     notFoundBundles.remove(symbolicName);
-//                             } catch (Exception e) {
-//                                     OsgiBootUtils.warn("Bundle " + symbolicName + " cannot be started: " + e.getMessage());
-//                                     if (OsgiBootUtils.isDebug())
-//                                             e.printStackTrace();
-//                                     // was found even if start failed
-//                                     notFoundBundles.remove(symbolicName);
-//                             }
-//             }
-//
-//             for (int i = 0; i < notFoundBundles.size(); i++)
-//                     OsgiBootUtils.warn("Bundle '" + notFoundBundles.get(i) + "' not started because it was not found.");
-//
-//             // monitors that all bundles are started
-//             long beginMonitor = System.currentTimeMillis();
-//             boolean allStarted = !(startedBundles.size() > 0);
-//             List<String> notStarted = new ArrayList<String>();
-//             while (!allStarted && (System.currentTimeMillis() - beginMonitor) < defaultTimeout) {
-//                     notStarted = new ArrayList<String>();
-//                     allStarted = true;
-//                     for (int i = 0; i < startedBundles.size(); i++) {
-//                             Bundle bundle = (Bundle) startedBundles.get(i);
-//                             // TODO check behaviour of lazs bundles
-//                             if (bundle.getState() != Bundle.ACTIVE) {
-//                                     allStarted = false;
-//                                     notStarted.add(bundle.getSymbolicName());
-//                             }
-//                     }
-//                     try {
-//                             Thread.sleep(100);
-//                     } catch (InterruptedException e) {
-//                             // silent
-//                     }
-//             }
-//             long duration = System.currentTimeMillis() - beginMonitor;
-//
-//             if (!allStarted)
-//                     for (int i = 0; i < notStarted.size(); i++)
-//                             OsgiBootUtils.warn("Bundle '" + notStarted.get(i) + "' not ACTIVE after " + (duration / 1000) + "s");
-//
-//             return allStarted;
-//     }
-
-//     /** Waits for a bundle to become active or resolved */
-//     @Deprecated
-//     private void waitForBundleResolvedOrActive(long startBegin, Bundle bundle) throws Exception {
-//             int originalState = bundle.getState();
-//             if ((originalState == Bundle.RESOLVED) || (originalState == Bundle.ACTIVE))
-//                     return;
-//
-//             String originalStateStr = OsgiBootUtils.stateAsString(originalState);
-//
-//             int currentState = bundle.getState();
-//             while (!(currentState == Bundle.RESOLVED || currentState == Bundle.ACTIVE)) {
-//                     long now = System.currentTimeMillis();
-//                     if ((now - startBegin) > defaultTimeout * 10)
-//                             throw new Exception("Bundle " + bundle.getSymbolicName() + " was not RESOLVED or ACTIVE after "
-//                                             + (now - startBegin) + "ms (originalState=" + originalStateStr + ", currentState="
-//                                             + OsgiBootUtils.stateAsString(currentState) + ")");
-//
-//                     try {
-//                             Thread.sleep(100l);
-//                     } catch (InterruptedException e) {
-//                             // silent
-//                     }
-//                     currentState = bundle.getState();
-//             }
-//     }
-
        /*
         * BUNDLE PATTERNS INSTALLATION
         */
@@ -691,16 +595,6 @@ public class OsgiBoot implements OsgiBootConstants {
 
                        distributionBundle = new DistributionBundle(baseUrl, distributionUrl, localCache);
                }
-               // if (baseUrl != null && !(distributionUrl.startsWith("http") ||
-               // distributionUrl.startsWith("file"))) {
-               // // relative url
-               // distributionBundle = new DistributionBundle(baseUrl, distributionUrl,
-               // localCache);
-               // } else {
-               // distributionBundle = new DistributionBundle(distributionUrl);
-               // if (baseUrl != null)
-               // distributionBundle.setBaseUrl(baseUrl);
-               // }
                distributionBundle.processUrl();
                return distributionBundle.listUrls();
        }
@@ -808,6 +702,7 @@ public class OsgiBoot implements OsgiBootConstants {
        private void refreshFramework() {
                Bundle systemBundle = bundleContext.getBundle(0);
                FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class);
+               // TODO deal with refresh breaking native loading (e.g SWT)
                frameworkWiring.refreshBundles(null);
        }
 
@@ -832,36 +727,8 @@ public class OsgiBoot implements OsgiBootConstants {
         * BEAN METHODS
         */
 
-//     public boolean getDebug() {
-//             return OsgiBootUtils.debug;
-//     }
-
-       // public void setDebug(boolean debug) {
-       // this.debug = debug;
-       // }
-
        public BundleContext getBundleContext() {
                return bundleContext;
        }
 
-//     public String getLocalCache() {
-//             return localCache;
-//     }
-
-       // public void setDefaultTimeout(long defaultTimeout) {
-       // this.defaultTimeout = defaultTimeout;
-       // }
-
-       // public boolean isExcludeSvn() {
-       // return excludeSvn;
-       // }
-       //
-       // public void setExcludeSvn(boolean excludeSvn) {
-       // this.excludeSvn = excludeSvn;
-       // }
-
-       /*
-        * INTERNAL CLASSES
-        */
-
 }
diff --git a/org.argeo.init/src/org/argeo/init/osgi/log4j.properties b/org.argeo.init/src/org/argeo/init/osgi/log4j.properties
deleted file mode 100644 (file)
index 1fcf25e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-log4j.rootLogger=WARN, console
-
-log4j.logger.org.argeo=INFO
-
-## Appenders
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c - [%t]%n
-
-log4j.appender.development=org.apache.log4j.ConsoleAppender
-log4j.appender.development.layout=org.apache.log4j.PatternLayout
-log4j.appender.development.layout.ConversionPattern=%d{ABSOLUTE} %m (%F:%L) [%t] %p %n
diff --git a/org.argeo.util/.classpath b/org.argeo.util/.classpath
deleted file mode 100644 (file)
index 4199cd3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
-               <attributes>
-                       <attribute name="module" value="true"/>
-               </attributes>
-       </classpathentry>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/org.argeo.util/.project b/org.argeo.util/.project
deleted file mode 100644 (file)
index 171ff88..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.util</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-               <nature>org.eclipse.pde.PluginNature</nature>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.util/META-INF/.gitignore b/org.argeo.util/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.util/bnd.bnd b/org.argeo.util/bnd.bnd
deleted file mode 100644 (file)
index 5f42f77..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Bundle-Activator: org.argeo.osgi.internal.EnterpriseActivator
-Bundle-ActivationPolicy: lazy
-
-Import-Package:        org.osgi.*;version=0.0.0,\
-!org.apache.commons.logging,\
-*                              
diff --git a/org.argeo.util/build.properties b/org.argeo.util/build.properties
deleted file mode 100644 (file)
index ae2abc5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-source.. = src/
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/osgi/internal/EnterpriseActivator.java b/org.argeo.util/src/org/argeo/osgi/internal/EnterpriseActivator.java
deleted file mode 100644 (file)
index bb495dd..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.argeo.osgi.internal;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-/**
- * Called to gather information about the OSGi runtime. Should not activate
- * anything else that canonical monitoring services (not creating implicit
- * APIs), which is the responsibility of higher levels.
- */
-public class EnterpriseActivator implements BundleActivator {
-
-       @Override
-       public void start(BundleContext context) throws Exception {
-       }
-
-       @Override
-       public void stop(BundleContext context) throws Exception {
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/provisioning/SimpleProvisioningService.java b/org.argeo.util/src/org/argeo/osgi/provisioning/SimpleProvisioningService.java
deleted file mode 100644 (file)
index c0ec290..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.argeo.osgi.provisioning;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.zip.ZipInputStream;
-
-import org.osgi.service.provisioning.ProvisioningService;
-
-public class SimpleProvisioningService implements ProvisioningService {
-       private Map<String, Object> map = Collections.synchronizedSortedMap(new TreeMap<>());
-
-       public SimpleProvisioningService() {
-               // update count
-               map.put(PROVISIONING_UPDATE_COUNT, 0);
-       }
-
-       @Override
-       public Dictionary<String, Object> getInformation() {
-               return new Information();
-       }
-
-       @Override
-       public synchronized void setInformation(Dictionary<String, ?> info) {
-               map.clear();
-               addInformation(info);
-       }
-
-       @Override
-       public synchronized void addInformation(Dictionary<String, ?> info) {
-               Enumeration<String> e = info.keys();
-               while (e.hasMoreElements()) {
-                       String key = e.nextElement();
-                       map.put(key, info.get(key));
-               }
-               incrementProvisioningUpdateCount();
-       }
-
-       protected synchronized void incrementProvisioningUpdateCount() {
-               Integer current = (Integer) map.get(PROVISIONING_UPDATE_COUNT);
-               Integer newValue = current + 1;
-               map.put(PROVISIONING_UPDATE_COUNT, newValue);
-       }
-
-       @Override
-       public synchronized void addInformation(ZipInputStream zis) throws IOException {
-               throw new UnsupportedOperationException();
-       }
-
-       class Information extends Dictionary<String, Object> {
-
-               @Override
-               public int size() {
-                       return map.size();
-               }
-
-               @Override
-               public boolean isEmpty() {
-                       return map.isEmpty();
-               }
-
-               @Override
-               public Enumeration<String> keys() {
-                       Iterator<String> it = map.keySet().iterator();
-                       return new Enumeration<String>() {
-
-                               @Override
-                               public boolean hasMoreElements() {
-                                       return it.hasNext();
-                               }
-
-                               @Override
-                               public String nextElement() {
-                                       return it.next();
-                               }
-
-                       };
-               }
-
-               @Override
-               public Enumeration<Object> elements() {
-                       Iterator<Object> it = map.values().iterator();
-                       return new Enumeration<Object>() {
-
-                               @Override
-                               public boolean hasMoreElements() {
-                                       return it.hasNext();
-                               }
-
-                               @Override
-                               public Object nextElement() {
-                                       return it.next();
-                               }
-
-                       };
-               }
-
-               @Override
-               public Object get(Object key) {
-                       return map.get(key);
-               }
-
-               @Override
-               public Object put(String key, Object value) {
-                       throw new UnsupportedOperationException();
-               }
-
-               @Override
-               public Object remove(Object key) {
-                       throw new UnsupportedOperationException();
-               }
-
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/provisioning/package-info.java b/org.argeo.util/src/org/argeo/osgi/provisioning/package-info.java
deleted file mode 100644 (file)
index 1859887..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** OSGi provisioning support. */
-package org.argeo.osgi.provisioning;
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingAuthorization.java b/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingAuthorization.java
deleted file mode 100644 (file)
index 05ba948..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.security.auth.x500.X500Principal;
-
-import org.osgi.service.useradmin.Authorization;
-
-/** An {@link Authorization} which combines roles form various auth sources. */
-class AggregatingAuthorization implements Authorization {
-       private final String name;
-       private final String displayName;
-       private final Set<String> systemRoles;
-       private final Set<String> roles;
-
-       public AggregatingAuthorization(String name, String displayName, Set<String> systemRoles, String[] roles) {
-               this.name = new X500Principal(name).getName();
-               this.displayName = displayName;
-               this.systemRoles = Collections.unmodifiableSet(new HashSet<>(systemRoles));
-               Set<String> temp = new HashSet<>();
-               for (String role : roles) {
-                       if (!temp.contains(role))
-                               temp.add(role);
-               }
-               this.roles = Collections.unmodifiableSet(temp);
-       }
-
-       @Override
-       public String getName() {
-               return name;
-       }
-
-       @Override
-       public boolean hasRole(String name) {
-               if (systemRoles.contains(name))
-                       return true;
-               if (roles.contains(name))
-                       return true;
-               return false;
-       }
-
-       @Override
-       public String[] getRoles() {
-               int size = systemRoles.size() + roles.size();
-               List<String> res = new ArrayList<String>(size);
-               res.addAll(systemRoles);
-               res.addAll(roles);
-               return res.toArray(new String[size]);
-       }
-
-       @Override
-       public int hashCode() {
-               if (name == null)
-                       return super.hashCode();
-               return name.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (!(obj instanceof Authorization))
-                       return false;
-               Authorization that = (Authorization) obj;
-               if (name == null)
-                       return that.getName() == null;
-               return name.equals(that.getName());
-       }
-
-       @Override
-       public String toString() {
-               return displayName;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java b/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java
deleted file mode 100644 (file)
index 83b2f17..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.osgi.useradmin.DirectoryUserAdmin.toLdapName;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeSet;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.DirectoryConf;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-/**
- * Aggregates multiple {@link UserDirectory} and integrates them with system
- * roles.
- */
-public class AggregatingUserAdmin implements UserAdmin {
-       private final LdapName systemRolesBaseDn;
-       private final LdapName tokensBaseDn;
-
-       // DAOs
-       private DirectoryUserAdmin systemRoles = null;
-       private DirectoryUserAdmin tokens = null;
-       private Map<LdapName, DirectoryUserAdmin> businessRoles = new HashMap<LdapName, DirectoryUserAdmin>();
-
-       // TODO rather use an empty constructor and an init method
-       public AggregatingUserAdmin(String systemRolesBaseDn, String tokensBaseDn) {
-               try {
-                       this.systemRolesBaseDn = new LdapName(systemRolesBaseDn);
-                       if (tokensBaseDn != null)
-                               this.tokensBaseDn = new LdapName(tokensBaseDn);
-                       else
-                               this.tokensBaseDn = null;
-               } catch (InvalidNameException e) {
-                       throw new IllegalStateException("Cannot initialize " + AggregatingUserAdmin.class, e);
-               }
-       }
-
-       @Override
-       public Role createRole(String name, int type) {
-               return findUserAdmin(name).createRole(name, type);
-       }
-
-       @Override
-       public boolean removeRole(String name) {
-               boolean actuallyDeleted = findUserAdmin(name).removeRole(name);
-               systemRoles.removeRole(name);
-               return actuallyDeleted;
-       }
-
-       @Override
-       public Role getRole(String name) {
-               return findUserAdmin(name).getRole(name);
-       }
-
-       @Override
-       public Role[] getRoles(String filter) throws InvalidSyntaxException {
-               List<Role> res = new ArrayList<Role>();
-               for (UserAdmin userAdmin : businessRoles.values()) {
-                       res.addAll(Arrays.asList(userAdmin.getRoles(filter)));
-               }
-               res.addAll(Arrays.asList(systemRoles.getRoles(filter)));
-               return res.toArray(new Role[res.size()]);
-       }
-
-       @Override
-       public User getUser(String key, String value) {
-               List<User> res = new ArrayList<User>();
-               for (UserAdmin userAdmin : businessRoles.values()) {
-                       User u = userAdmin.getUser(key, value);
-                       if (u != null)
-                               res.add(u);
-               }
-               // Note: node roles cannot contain users, so it is not searched
-               return res.size() == 1 ? res.get(0) : null;
-       }
-
-       /** Builds an authorisation by scanning all referentials. */
-       @Override
-       public Authorization getAuthorization(User user) {
-               if (user == null) {// anonymous
-                       return systemRoles.getAuthorization(null);
-               }
-               DirectoryUserAdmin userReferentialOfThisUser = findUserAdmin(user.getName());
-               Authorization rawAuthorization = userReferentialOfThisUser.getAuthorization(user);
-               User retrievedUser = (User) userReferentialOfThisUser.getRole(user.getName());
-               String usernameToUse;
-               String displayNameToUse;
-               if (user instanceof Group) {
-                       // TODO check whether this is still working
-                       String ownerDn = TokenUtils.userDn((Group) user);
-                       if (ownerDn != null) {// tokens
-                               UserAdmin ownerUserAdmin = findUserAdmin(ownerDn);
-                               User ownerUser = (User) ownerUserAdmin.getRole(ownerDn);
-                               usernameToUse = ownerDn;
-                               displayNameToUse = LdifAuthorization.extractDisplayName(ownerUser);
-                       } else {
-                               usernameToUse = rawAuthorization.getName();
-                               displayNameToUse = rawAuthorization.toString();
-                       }
-               } else {// regular users
-                       usernameToUse = rawAuthorization.getName();
-                       displayNameToUse = rawAuthorization.toString();
-               }
-
-               // gather roles from other referentials
-               List<String> allRoles = new ArrayList<>(Arrays.asList(rawAuthorization.getRoles()));
-               for (LdapName otherBaseDn : businessRoles.keySet()) {
-                       if (otherBaseDn.equals(userReferentialOfThisUser.getBaseDn()))
-                               continue;
-                       DirectoryUserAdmin otherUserAdmin = userAdminToUse(user, businessRoles.get(otherBaseDn));
-                       if (otherUserAdmin == null)
-                               continue;
-                       Authorization auth = otherUserAdmin.getAuthorization(retrievedUser);
-                       allRoles.addAll(Arrays.asList(auth.getRoles()));
-
-               }
-
-               // integrate system roles
-               final DirectoryUserAdmin userAdminToUse = userAdminToUse(retrievedUser, userReferentialOfThisUser);
-               Objects.requireNonNull(userAdminToUse);
-
-               try {
-                       Set<String> sysRoles = new HashSet<String>();
-                       for (String role : rawAuthorization.getRoles()) {
-                               User userOrGroup = (User) userAdminToUse.getRole(role);
-                               Authorization auth = systemRoles.getAuthorization(userOrGroup);
-                               systemRoles: for (String systemRole : auth.getRoles()) {
-                                       if (role.equals(systemRole))
-                                               continue systemRoles;
-                                       sysRoles.add(systemRole);
-                               }
-//                     sysRoles.addAll(Arrays.asList(auth.getRoles()));
-                       }
-                       addAbstractSystemRoles(rawAuthorization, sysRoles);
-                       Authorization authorization = new AggregatingAuthorization(usernameToUse, displayNameToUse, sysRoles,
-                                       allRoles.toArray(new String[allRoles.size()]));
-                       return authorization;
-               } finally {
-                       if (userAdminToUse != null && userAdminToUse.isScoped()) {
-                               userAdminToUse.destroy();
-                       }
-               }
-       }
-
-       /** Decide whether to scope or not */
-       private DirectoryUserAdmin userAdminToUse(User user, DirectoryUserAdmin userAdmin) {
-               if (user instanceof DirectoryUser) {
-                       return userAdmin;
-               } else if (user instanceof AuthenticatingUser) {
-                       return userAdmin.scope(user).orElse(null);
-               } else {
-                       throw new IllegalArgumentException("Unsupported user type " + user.getClass());
-               }
-
-       }
-
-       /**
-        * Enrich with application-specific roles which are strictly programmatic, such
-        * as anonymous/user semantics.
-        */
-       protected void addAbstractSystemRoles(Authorization rawAuthorization, Set<String> sysRoles) {
-
-       }
-
-       //
-       // USER ADMIN AGGREGATOR
-       //
-       protected void addUserDirectory(UserDirectory ud) {
-               if (!(ud instanceof DirectoryUserAdmin))
-                       throw new IllegalArgumentException("Only " + DirectoryUserAdmin.class.getName() + " is supported");
-               DirectoryUserAdmin userDirectory = (DirectoryUserAdmin) ud;
-               String basePath = userDirectory.getBase();
-               if (isSystemRolesBaseDn(basePath)) {
-                       this.systemRoles = userDirectory;
-                       systemRoles.setExternalRoles(this);
-               } else if (isTokensBaseDn(basePath)) {
-                       this.tokens = userDirectory;
-                       tokens.setExternalRoles(this);
-               } else {
-                       LdapName baseDn = toLdapName(basePath);
-                       if (businessRoles.containsKey(baseDn))
-                               throw new IllegalStateException("There is already a user admin for " + baseDn);
-                       businessRoles.put(baseDn, userDirectory);
-               }
-               userDirectory.init();
-               postAdd(userDirectory);
-       }
-
-       /** Called after a new user directory has been added */
-       protected void postAdd(UserDirectory userDirectory) {
-       }
-
-       private DirectoryUserAdmin findUserAdmin(String name) {
-               try {
-                       return findUserAdmin(new LdapName(name));
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Badly formatted name " + name, e);
-               }
-       }
-
-       private DirectoryUserAdmin findUserAdmin(LdapName name) {
-               if (name.startsWith(systemRolesBaseDn))
-                       return systemRoles;
-               if (tokensBaseDn != null && name.startsWith(tokensBaseDn))
-                       return tokens;
-               List<DirectoryUserAdmin> res = new ArrayList<>(1);
-               userDirectories: for (LdapName baseDn : businessRoles.keySet()) {
-                       DirectoryUserAdmin userDirectory = businessRoles.get(baseDn);
-                       if (name.startsWith(baseDn)) {
-                               if (userDirectory.isDisabled())
-                                       continue userDirectories;
-//                             if (res.isEmpty()) {
-                               res.add(userDirectory);
-//                             } else {
-//                                     for (AbstractUserDirectory ud : res) {
-//                                             LdapName bd = ud.getBaseDn();
-//                                             if (userDirectory.getBaseDn().startsWith(bd)) {
-//                                                     // child user directory
-//                                             }
-//                                     }
-//                             }
-                       }
-               }
-               if (res.size() == 0)
-                       throw new IllegalStateException("Cannot find user admin for " + name);
-               if (res.size() > 1)
-                       throw new IllegalStateException("Multiple user admin found for " + name);
-               return res.get(0);
-       }
-
-       protected boolean isSystemRolesBaseDn(String basePath) {
-               return toLdapName(basePath).equals(systemRolesBaseDn);
-       }
-
-       protected boolean isTokensBaseDn(String basePath) {
-               return tokensBaseDn != null && toLdapName(basePath).equals(tokensBaseDn);
-       }
-
-//     protected Dictionary<String, Object> currentState() {
-//             Dictionary<String, Object> res = new Hashtable<String, Object>();
-//             // res.put(NodeConstants.CN, NodeConstants.DEFAULT);
-//             for (LdapName name : businessRoles.keySet()) {
-//                     AbstractUserDirectory userDirectory = businessRoles.get(name);
-//                     String uri = UserAdminConf.propertiesAsUri(userDirectory.getProperties()).toString();
-//                     res.put(uri, "");
-//             }
-//             return res;
-//     }
-
-       public void start() {
-               if (systemRoles == null) {
-                       // TODO do we really need separate system roles?
-                       Hashtable<String, Object> properties = new Hashtable<>();
-                       properties.put(DirectoryConf.baseDn.name(), "ou=roles,ou=system");
-                       systemRoles = new DirectoryUserAdmin(properties);
-               }
-       }
-
-       public void stop() {
-               for (LdapName name : businessRoles.keySet()) {
-                       DirectoryUserAdmin userDirectory = businessRoles.get(name);
-                       destroy(userDirectory);
-               }
-               businessRoles.clear();
-               businessRoles = null;
-               destroy(systemRoles);
-               systemRoles = null;
-       }
-
-       private void destroy(DirectoryUserAdmin userDirectory) {
-               preDestroy(userDirectory);
-               userDirectory.destroy();
-       }
-
-//     protected void removeUserDirectory(UserDirectory userDirectory) {
-//             LdapName baseDn = toLdapName(userDirectory.getContext());
-//             businessRoles.remove(baseDn);
-//             if (userDirectory instanceof DirectoryUserAdmin)
-//                     destroy((DirectoryUserAdmin) userDirectory);
-//     }
-
-       @Deprecated
-       protected void removeUserDirectory(String basePath) {
-               if (isSystemRolesBaseDn(basePath))
-                       throw new IllegalArgumentException("System roles cannot be removed ");
-               LdapName baseDn = toLdapName(basePath);
-               if (!businessRoles.containsKey(baseDn))
-                       throw new IllegalStateException("No user directory registered for " + baseDn);
-               DirectoryUserAdmin userDirectory = businessRoles.remove(baseDn);
-               destroy(userDirectory);
-       }
-
-       /**
-        * Called before each user directory is destroyed, so that additional actions
-        * can be performed.
-        */
-       protected void preDestroy(UserDirectory userDirectory) {
-       }
-
-       public Set<UserDirectory> getUserDirectories() {
-               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getBase().compareTo(o2.getBase()));
-               res.addAll(businessRoles.values());
-               res.add(systemRoles);
-               return res;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/AuthenticatingUser.java b/org.argeo.util/src/org/argeo/osgi/useradmin/AuthenticatingUser.java
deleted file mode 100644 (file)
index ba1f3f7..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.DirectoryDigestUtils;
-import org.osgi.service.useradmin.User;
-
-/**
- * A special user type used during authentication in order to provide the
- * credentials required for scoping the user admin.
- */
-public class AuthenticatingUser implements User {
-       /** From com.sun.security.auth.module.*LoginModule */
-       public final static String SHARED_STATE_NAME = "javax.security.auth.login.name";
-       /** From com.sun.security.auth.module.*LoginModule */
-       public final static String SHARED_STATE_PWD = "javax.security.auth.login.password";
-
-       private final String name;
-       private final Dictionary<String, Object> credentials;
-
-       public AuthenticatingUser(LdapName name) {
-               if (name == null)
-                       throw new NullPointerException("Provided name cannot be null.");
-               this.name = name.toString();
-               this.credentials = new Hashtable<>();
-       }
-
-       public AuthenticatingUser(String name, Dictionary<String, Object> credentials) {
-               this.name = name;
-               this.credentials = credentials;
-       }
-
-       public AuthenticatingUser(String name, char[] password) {
-               if (name == null)
-                       throw new NullPointerException("Provided name cannot be null.");
-               this.name = name;
-               credentials = new Hashtable<>();
-               credentials.put(SHARED_STATE_NAME, name);
-               byte[] pwd = DirectoryDigestUtils.charsToBytes(password);
-               credentials.put(SHARED_STATE_PWD, pwd);
-       }
-
-       @Override
-       public String getName() {
-               return name;
-       }
-
-       @Override
-       public int getType() {
-               return User.USER;
-       }
-
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       @Override
-       public Dictionary getProperties() {
-               throw new UnsupportedOperationException();
-       }
-
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       @Override
-       public Dictionary getCredentials() {
-               return credentials;
-       }
-
-       @Override
-       public boolean hasCredential(String key, Object value) {
-               throw new UnsupportedOperationException();
-       }
-
-       @Override
-       public int hashCode() {
-               return name.hashCode();
-       }
-
-       @Override
-       public String toString() {
-               return "Authenticating user " + name;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryGroup.java b/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryGroup.java
deleted file mode 100644 (file)
index 1d58a2d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import org.osgi.service.useradmin.Group;
-
-/** A group in a user directroy. */
-interface DirectoryGroup extends Group, DirectoryUser {
-//     List<LdapName> getMemberNames();
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUser.java b/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUser.java
deleted file mode 100644 (file)
index 18b28a2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import org.osgi.service.useradmin.User;
-
-/** A user in a user directory. */
-interface DirectoryUser extends User {
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUserAdmin.java b/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUserAdmin.java
deleted file mode 100644 (file)
index 3903a23..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.util.naming.LdapAttrs.objectClass;
-import static org.argeo.util.naming.LdapObjs.extensibleObject;
-import static org.argeo.util.naming.LdapObjs.inetOrgPerson;
-import static org.argeo.util.naming.LdapObjs.organizationalPerson;
-import static org.argeo.util.naming.LdapObjs.person;
-import static org.argeo.util.naming.LdapObjs.top;
-
-import java.net.URI;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-
-import javax.naming.Context;
-import javax.naming.InvalidNameException;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosTicket;
-
-import org.argeo.util.CurrentSubject;
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.directory.DirectoryDigestUtils;
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.directory.ldap.AbstractLdapDirectory;
-import org.argeo.util.directory.ldap.LdapDao;
-import org.argeo.util.directory.ldap.LdapEntry;
-import org.argeo.util.directory.ldap.LdapEntryWorkingCopy;
-import org.argeo.util.directory.ldap.LdapNameUtils;
-import org.argeo.util.directory.ldap.LdifDao;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-/** Base class for a {@link UserDirectory}. */
-public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdmin, UserDirectory {
-
-       private UserAdmin externalRoles;
-
-       // Transaction
-       public DirectoryUserAdmin(URI uriArg, Dictionary<String, ?> props) {
-               this(uriArg, props, false);
-       }
-
-       public DirectoryUserAdmin(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
-               super(uriArg, props, scoped);
-       }
-
-       public DirectoryUserAdmin(Dictionary<String, ?> props) {
-               this(null, props);
-       }
-
-       /*
-        * ABSTRACT METHODS
-        */
-
-       protected Optional<DirectoryUserAdmin> scope(User user) {
-               if (getDirectoryDao() instanceof LdapDao) {
-                       return scopeLdap(user);
-               } else if (getDirectoryDao() instanceof LdifDao) {
-                       return scopeLdif(user);
-               } else {
-                       throw new IllegalStateException("Unsupported DAO " + getDirectoryDao().getClass());
-               }
-       }
-
-       protected Optional<DirectoryUserAdmin> scopeLdap(User user) {
-               Dictionary<String, Object> credentials = user.getCredentials();
-               String username = (String) credentials.get(SHARED_STATE_USERNAME);
-               if (username == null)
-                       username = user.getName();
-               Dictionary<String, Object> properties = cloneConfigProperties();
-               properties.put(Context.SECURITY_PRINCIPAL, username.toString());
-               Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
-               byte[] pwd = (byte[]) pwdCred;
-               if (pwd != null) {
-                       char[] password = DirectoryDigestUtils.bytesToChars(pwd);
-                       properties.put(Context.SECURITY_CREDENTIALS, new String(password));
-               } else {
-                       properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
-               }
-               DirectoryUserAdmin scopedDirectory = new DirectoryUserAdmin(null, properties, true);
-               scopedDirectory.init();
-               // check connection
-               if (!scopedDirectory.getDirectoryDao().checkConnection())
-                       return Optional.empty();
-               return Optional.of(scopedDirectory);
-       }
-
-       protected Optional<DirectoryUserAdmin> scopeLdif(User user) {
-               Dictionary<String, Object> credentials = user.getCredentials();
-               String username = (String) credentials.get(SHARED_STATE_USERNAME);
-               if (username == null)
-                       username = user.getName();
-               Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
-               byte[] pwd = (byte[]) pwdCred;
-               if (pwd != null) {
-                       char[] password = DirectoryDigestUtils.bytesToChars(pwd);
-                       User directoryUser = (User) getRole(username);
-                       if (!directoryUser.hasCredential(null, password))
-                               throw new IllegalStateException("Invalid credentials");
-               } else {
-                       throw new IllegalStateException("Password is required");
-               }
-               Dictionary<String, Object> properties = cloneConfigProperties();
-               properties.put(DirectoryConf.readOnly.name(), "true");
-               DirectoryUserAdmin scopedUserAdmin = new DirectoryUserAdmin(null, properties, true);
-               // FIXME do it better
-               ((LdifDao) getDirectoryDao()).scope((LdifDao) scopedUserAdmin.getDirectoryDao());
-               // no need to check authentication
-               scopedUserAdmin.init();
-               return Optional.of(scopedUserAdmin);
-       }
-
-       @Override
-       public String getRolePath(Role role) {
-               return nameToRelativePath(LdapNameUtils.toLdapName(role.getName()));
-       }
-
-       @Override
-       public String getRoleSimpleName(Role role) {
-               LdapName dn = LdapNameUtils.toLdapName(role.getName());
-               String name = LdapNameUtils.getLastRdnValue(dn);
-               return name;
-       }
-
-       @Override
-       public Role getRoleByPath(String path) {
-               LdapEntry entry = doGetRole(pathToName(path));
-               if (!(entry instanceof Role)) {
-                       return null;
-//                     throw new IllegalStateException("Path must be a UserAdmin Role.");
-               } else {
-                       return (Role) entry;
-               }
-       }
-
-       protected List<Role> getAllRoles(DirectoryUser user) {
-               List<Role> allRoles = new ArrayList<Role>();
-               if (user != null) {
-                       collectRoles((LdapEntry) user, allRoles);
-                       allRoles.add(user);
-               } else
-                       collectAnonymousRoles(allRoles);
-               return allRoles;
-       }
-
-       private void collectRoles(LdapEntry user, List<Role> allRoles) {
-               List<LdapEntry> allEntries = new ArrayList<>();
-               LdapEntry entry = user;
-               collectGroups(entry, allEntries);
-               for (LdapEntry e : allEntries) {
-                       if (e instanceof Role)
-                               allRoles.add((Role) e);
-               }
-       }
-
-       private void collectAnonymousRoles(List<Role> allRoles) {
-               // TODO gather anonymous roles
-       }
-
-       // USER ADMIN
-       @Override
-       public Role getRole(String name) {
-               return (Role) doGetRole(toLdapName(name));
-       }
-
-       @Override
-       public Role[] getRoles(String filter) throws InvalidSyntaxException {
-               List<? extends Role> res = getRoles(getBaseDn(), filter, true);
-               return res.toArray(new Role[res.size()]);
-       }
-
-       List<DirectoryUser> getRoles(LdapName searchBase, String filter, boolean deep) throws InvalidSyntaxException {
-               LdapEntryWorkingCopy wc = getWorkingCopy();
-//             Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
-               List<LdapEntry> searchRes = getDirectoryDao().doGetEntries(searchBase, filter, deep);
-               List<DirectoryUser> res = new ArrayList<>();
-               for (LdapEntry entry : searchRes)
-                       res.add((DirectoryUser) entry);
-               if (wc != null) {
-                       for (Iterator<DirectoryUser> it = res.iterator(); it.hasNext();) {
-                               DirectoryUser user = (DirectoryUser) it.next();
-                               LdapName dn = LdapNameUtils.toLdapName(user.getName());
-                               if (wc.getDeletedData().containsKey(dn))
-                                       it.remove();
-                       }
-                       Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
-                       for (LdapEntry ldapEntry : wc.getNewData().values()) {
-                               DirectoryUser user = (DirectoryUser) ldapEntry;
-                               if (f == null || f.match(user.getProperties()))
-                                       res.add(user);
-                       }
-                       // no need to check modified users,
-                       // since doGetRoles was already based on the modified attributes
-               }
-               return res;
-       }
-
-       @Override
-       public User getUser(String key, String value) {
-               // TODO check value null or empty
-               List<DirectoryUser> collectedUsers = new ArrayList<DirectoryUser>();
-               if (key != null) {
-                       doGetUser(key, value, collectedUsers);
-               } else {
-                       throw new IllegalArgumentException("Key cannot be null");
-               }
-
-               if (collectedUsers.size() == 1) {
-                       return collectedUsers.get(0);
-               } else if (collectedUsers.size() > 1) {
-                       // log.warn(collectedUsers.size() + " users for " + (key != null ? key + "=" :
-                       // "") + value);
-               }
-               return null;
-       }
-
-       protected void doGetUser(String key, String value, List<DirectoryUser> collectedUsers) {
-               String f = "(" + key + "=" + value + ")";
-               List<LdapEntry> users = getDirectoryDao().doGetEntries(getBaseDn(), f, true);
-               for (LdapEntry entry : users)
-                       collectedUsers.add((DirectoryUser) entry);
-       }
-
-       @Override
-       public Authorization getAuthorization(User user) {
-               if (user == null) {// anonymous
-                       return new LdifAuthorization(user, getAllRoles(null));
-               }
-               LdapName userName = toLdapName(user.getName());
-               if (isExternal(userName) && user instanceof LdapEntry) {
-                       List<Role> allRoles = new ArrayList<Role>();
-                       collectRoles((LdapEntry) user, allRoles);
-                       return new LdifAuthorization(user, allRoles);
-               } else {
-
-                       Subject currentSubject = CurrentSubject.current();
-                       if (currentSubject != null //
-                                       && getRealm().isPresent() //
-                                       && !currentSubject.getPrivateCredentials(Authorization.class).isEmpty() //
-                                       && !currentSubject.getPrivateCredentials(KerberosTicket.class).isEmpty()) //
-                       {
-                               // TODO not only Kerberos but also bind scope with kept password ?
-                               Authorization auth = currentSubject.getPrivateCredentials(Authorization.class).iterator().next();
-                               // bind with authenticating user
-                               DirectoryUserAdmin scopedUserAdmin = CurrentSubject.callAs(currentSubject, () -> {
-                                       return scope(new AuthenticatingUser(auth.getName(), new Hashtable<>())).orElseThrow();
-                               });
-                               return getAuthorizationFromScoped(scopedUserAdmin, user);
-                       }
-
-                       if (user instanceof DirectoryUser) {
-                               return new LdifAuthorization(user, getAllRoles((DirectoryUser) user));
-                       } else {
-                               // bind with authenticating user
-                               DirectoryUserAdmin scopedUserAdmin = scope(user).orElseThrow();
-                               return getAuthorizationFromScoped(scopedUserAdmin, user);
-                       }
-               }
-       }
-
-       private Authorization getAuthorizationFromScoped(DirectoryUserAdmin scopedUserAdmin, User user) {
-               try {
-                       DirectoryUser directoryUser = (DirectoryUser) scopedUserAdmin.getRole(user.getName());
-                       if (directoryUser == null)
-                               throw new IllegalStateException("No scoped user found for " + user);
-                       LdifAuthorization authorization = new LdifAuthorization(directoryUser,
-                                       scopedUserAdmin.getAllRoles(directoryUser));
-                       return authorization;
-               } finally {
-                       scopedUserAdmin.destroy();
-               }
-       }
-
-       @Override
-       public Role createRole(String name, int type) {
-               checkEdit();
-               LdapEntryWorkingCopy wc = getWorkingCopy();
-               LdapName dn = toLdapName(name);
-               if ((getDirectoryDao().entryExists(dn) && !wc.getDeletedData().containsKey(dn))
-                               || wc.getNewData().containsKey(dn))
-                       throw new IllegalArgumentException("Already a role " + name);
-               BasicAttributes attrs = new BasicAttributes(true);
-               // attrs.put(LdifName.dn.name(), dn.toString());
-               Rdn nameRdn = dn.getRdn(dn.size() - 1);
-               // TODO deal with multiple attr RDN
-               attrs.put(nameRdn.getType(), nameRdn.getValue());
-               if (wc.getDeletedData().containsKey(dn)) {
-                       wc.getDeletedData().remove(dn);
-                       wc.getModifiedData().put(dn, attrs);
-                       return getRole(name);
-               } else {
-                       wc.getModifiedData().put(dn, attrs);
-                       LdapEntry newRole = doCreateRole(dn, type, attrs);
-                       wc.getNewData().put(dn, newRole);
-                       return (Role) newRole;
-               }
-       }
-
-       private LdapEntry doCreateRole(LdapName dn, int type, Attributes attrs) {
-               LdapEntry newRole;
-               BasicAttribute objClass = new BasicAttribute(objectClass.name());
-               if (type == Role.USER) {
-                       String userObjClass = getUserObjectClass();
-                       objClass.add(userObjClass);
-                       if (inetOrgPerson.name().equals(userObjClass)) {
-                               objClass.add(organizationalPerson.name());
-                               objClass.add(person.name());
-                       } else if (organizationalPerson.name().equals(userObjClass)) {
-                               objClass.add(person.name());
-                       }
-                       objClass.add(top.name());
-                       objClass.add(extensibleObject.name());
-                       attrs.put(objClass);
-                       newRole = newUser(dn);
-               } else if (type == Role.GROUP) {
-                       String groupObjClass = getGroupObjectClass();
-                       objClass.add(groupObjClass);
-                       // objClass.add(LdifName.extensibleObject.name());
-                       objClass.add(top.name());
-                       attrs.put(objClass);
-                       newRole = newGroup(dn);
-               } else
-                       throw new IllegalArgumentException("Unsupported type " + type);
-               return newRole;
-       }
-
-       @Override
-       public boolean removeRole(String name) {
-               return removeEntry(LdapNameUtils.toLdapName(name));
-       }
-
-       /*
-        * HIERARCHY
-        */
-       @Override
-       public HierarchyUnit getHierarchyUnit(Role role) {
-               LdapName dn = LdapNameUtils.toLdapName(role.getName());
-               LdapName huDn = LdapNameUtils.getParent(dn);
-               HierarchyUnit hierarchyUnit = getDirectoryDao().doGetHierarchyUnit(huDn);
-               if (hierarchyUnit == null)
-                       throw new IllegalStateException("No hierarchy unit found for " + role);
-               return hierarchyUnit;
-       }
-
-       @Override
-       public Iterable<? extends Role> getHierarchyUnitRoles(HierarchyUnit hierarchyUnit, String filter, boolean deep) {
-               LdapName dn = LdapNameUtils.toLdapName(hierarchyUnit.getBase());
-               try {
-                       return getRoles(dn, filter, deep);
-               } catch (InvalidSyntaxException e) {
-                       throw new IllegalArgumentException("Cannot filter " + filter + " " + dn, e);
-               }
-       }
-
-       /*
-        * ROLES CREATION
-        */
-       protected LdapEntry newUser(LdapName name) {
-               // TODO support devices, applications, etc.
-               return new LdifUser(this, name);
-       }
-
-       protected LdapEntry newGroup(LdapName name) {
-               return new LdifGroup(this, name);
-
-       }
-
-       // GETTERS
-       protected UserAdmin getExternalRoles() {
-               return externalRoles;
-       }
-
-       public void setExternalRoles(UserAdmin externalRoles) {
-               this.externalRoles = externalRoles;
-       }
-
-       /*
-        * STATIC UTILITIES
-        */
-       static LdapName toLdapName(String name) {
-               try {
-                       return new LdapName(name);
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException(name + " is not an LDAP name", e);
-               }
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java
deleted file mode 100644 (file)
index d7f6ad9..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.List;
-
-import org.argeo.util.naming.LdapAttrs;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-
-/** Basic authorization. */
-class LdifAuthorization implements Authorization {
-       private final String name;
-       private final String displayName;
-       private final List<String> allRoles;
-
-       public LdifAuthorization(User user, List<Role> allRoles) {
-               if (user == null) {
-                       this.name = null;
-                       this.displayName = "anonymous";
-               } else {
-                       this.name = user.getName();
-                       this.displayName = extractDisplayName(user);
-               }
-               // roles
-               String[] roles = new String[allRoles.size()];
-               for (int i = 0; i < allRoles.size(); i++) {
-                       roles[i] = allRoles.get(i).getName();
-               }
-               this.allRoles = Collections.unmodifiableList(Arrays.asList(roles));
-       }
-
-       @Override
-       public String getName() {
-               return name;
-       }
-
-       @Override
-       public boolean hasRole(String name) {
-               return allRoles.contains(name);
-       }
-
-       @Override
-       public String[] getRoles() {
-               return allRoles.toArray(new String[allRoles.size()]);
-       }
-
-       @Override
-       public int hashCode() {
-               if (name == null)
-                       return super.hashCode();
-               return name.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (!(obj instanceof Authorization))
-                       return false;
-               Authorization that = (Authorization) obj;
-               if (name == null)
-                       return that.getName() == null;
-               return name.equals(that.getName());
-       }
-
-       @Override
-       public String toString() {
-               return displayName;
-       }
-
-       final static String extractDisplayName(User user) {
-               Dictionary<String, Object> props = user.getProperties();
-               Object displayName = props.get(LdapAttrs.displayName.name());
-               if (displayName == null)
-                       displayName = props.get(LdapAttrs.cn.name());
-               if (displayName == null)
-                       displayName = props.get(LdapAttrs.uid.name());
-               if (displayName == null)
-                       displayName = user.getName();
-               if (displayName == null)
-                       throw new IllegalStateException("Cannot set display name for " + user);
-               return displayName.toString();
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java
deleted file mode 100644 (file)
index bdf34aa..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.naming.InvalidNameException;
-import javax.naming.directory.Attribute;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.ldap.AbstractLdapDirectory;
-import org.osgi.service.useradmin.Role;
-
-/** Directory group implementation */
-class LdifGroup extends LdifUser implements DirectoryGroup {
-       private final String memberAttributeId;
-
-       LdifGroup(AbstractLdapDirectory userAdmin, LdapName dn) {
-               super(userAdmin, dn);
-               memberAttributeId = userAdmin.getMemberAttributeId();
-       }
-
-       @Override
-       public boolean addMember(Role role) {
-               try {
-                       Role foundRole = findRole(new LdapName(role.getName()));
-                       if (foundRole == null)
-                               throw new UnsupportedOperationException(
-                                               "Adding role " + role.getName() + " is unsupported within this context.");
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Role name" + role.getName() + " is badly formatted");
-               }
-
-               getUserAdmin().checkEdit();
-               if (!isEditing())
-                       startEditing();
-
-               Attribute member = getAttributes().get(memberAttributeId);
-               if (member != null) {
-                       if (member.contains(role.getName()))
-                               return false;
-                       else
-                               member.add(role.getName());
-               } else
-                       getAttributes().put(memberAttributeId, role.getName());
-               return true;
-       }
-
-       @Override
-       public boolean addRequiredMember(Role role) {
-               throw new UnsupportedOperationException();
-       }
-
-       @Override
-       public boolean removeMember(Role role) {
-               getUserAdmin().checkEdit();
-               if (!isEditing())
-                       startEditing();
-
-               Attribute member = getAttributes().get(memberAttributeId);
-               if (member != null) {
-                       if (!member.contains(role.getName()))
-                               return false;
-                       member.remove(role.getName());
-                       return true;
-               } else
-                       return false;
-       }
-
-       @Override
-       public Role[] getMembers() {
-               List<Role> directMembers = new ArrayList<Role>();
-               for (LdapName ldapName : getReferences(memberAttributeId)) {
-                       Role role = findRole(ldapName);
-                       if (role == null) {
-                               throw new IllegalStateException("Role " + ldapName + " not found.");
-                       }
-                       directMembers.add(role);
-               }
-               return directMembers.toArray(new Role[directMembers.size()]);
-       }
-
-       /**
-        * Whether a role with this name can be found from this context.
-        * 
-        * @return The related {@link Role} or <code>null</code>.
-        */
-       protected Role findRole(LdapName ldapName) {
-               Role role = getUserAdmin().getRole(ldapName.toString());
-               if (role == null) {
-                       if (getUserAdmin().getExternalRoles() != null)
-                               role = getUserAdmin().getExternalRoles().getRole(ldapName.toString());
-               }
-               return role;
-       }
-
-//     @Override
-//     public List<LdapName> getMemberNames() {
-//             Attribute memberAttribute = getAttributes().get(memberAttributeId);
-//             if (memberAttribute == null)
-//                     return new ArrayList<LdapName>();
-//             try {
-//                     List<LdapName> roles = new ArrayList<LdapName>();
-//                     NamingEnumeration<?> values = memberAttribute.getAll();
-//                     while (values.hasMore()) {
-//                             LdapName dn = new LdapName(values.next().toString());
-//                             roles.add(dn);
-//                     }
-//                     return roles;
-//             } catch (NamingException e) {
-//                     throw new IllegalStateException("Cannot get members", e);
-//             }
-//     }
-
-       @Override
-       public Role[] getRequiredMembers() {
-               throw new UnsupportedOperationException();
-       }
-
-       @Override
-       public int getType() {
-               return GROUP;
-       }
-
-       protected DirectoryUserAdmin getUserAdmin() {
-               return (DirectoryUserAdmin) getDirectory();
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java
deleted file mode 100644 (file)
index 0b07c75..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.ldap.AbstractLdapDirectory;
-import org.argeo.util.directory.ldap.DefaultLdapEntry;
-
-/** Directory user implementation */
-class LdifUser extends DefaultLdapEntry implements DirectoryUser {
-       LdifUser(AbstractLdapDirectory userAdmin, LdapName dn) {
-               super(userAdmin, dn);
-       }
-
-       @Override
-       public String getName() {
-               return getDn().toString();
-       }
-
-       @Override
-       public int getType() {
-               return USER;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java b/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java
deleted file mode 100644 (file)
index 5d7e97d..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.directory.ldap.AbstractLdapDirectory;
-import org.argeo.util.directory.ldap.AbstractLdapDirectoryDao;
-import org.argeo.util.directory.ldap.LdapEntry;
-import org.argeo.util.directory.ldap.LdapEntryWorkingCopy;
-import org.argeo.util.naming.LdapAttrs;
-
-/** Pseudo user directory to be used when logging in as OS user. */
-public class OsUserDirectory extends AbstractLdapDirectoryDao {
-       private final String osUsername = System.getProperty("user.name");
-       private final LdapName osUserDn;
-       private final LdapEntry osUser;
-
-       public OsUserDirectory(AbstractLdapDirectory directory) {
-               super(directory);
-               try {
-                       osUserDn = new LdapName(LdapAttrs.uid.name() + "=" + osUsername + "," + directory.getUserBaseRdn() + ","
-                                       + directory.getBaseDn());
-//                     Attributes attributes = new BasicAttributes();
-//                     attributes.put(LdapAttrs.uid.name(), osUsername);
-                       osUser = newUser(osUserDn);
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot create system user", e);
-               }
-       }
-
-       @Override
-       public List<LdapName> getDirectGroups(LdapName dn) {
-               return new ArrayList<>();
-       }
-
-       @Override
-       public boolean entryExists(LdapName dn) {
-               return osUserDn.equals(dn);
-       }
-
-       @Override
-       public boolean checkConnection() {
-               return true;
-       }
-
-       @Override
-       public LdapEntry doGetEntry(LdapName key) throws NameNotFoundException {
-               if (osUserDn.equals(key))
-                       return osUser;
-               else
-                       throw new NameNotFoundException("Not an OS role");
-       }
-
-       @Override
-       public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
-               List<LdapEntry> res = new ArrayList<>();
-//             if (f == null || f.match(osUser.getProperties()))
-               res.add(osUser);
-               return res;
-       }
-
-       @Override
-       public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
-               return null;
-       }
-
-       @Override
-       public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
-               return new ArrayList<>();
-       }
-
-       public void prepare(LdapEntryWorkingCopy wc) {
-
-       }
-
-       public void commit(LdapEntryWorkingCopy wc) {
-
-       }
-
-       public void rollback(LdapEntryWorkingCopy wc) {
-
-       }
-
-       @Override
-       public void init() {
-               // TODO Auto-generated method stub
-
-       }
-
-       @Override
-       public void destroy() {
-               // TODO Auto-generated method stub
-
-       }
-
-       @Override
-       public Attributes doGetAttributes(LdapName name) {
-               try {
-                       return doGetEntry(name).getAttributes();
-               } catch (NameNotFoundException e) {
-                       throw new IllegalStateException(name + " doe not exist in " + getDirectory().getBaseDn(), e);
-               }
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserUtils.java b/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserUtils.java
deleted file mode 100644 (file)
index 5d0cbf6..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.security.NoSuchAlgorithmException;
-import java.security.URIParameter;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.Configuration;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-/** Log in based on JDK-provided OS integration. */
-public class OsUserUtils {
-       private final static String LOGIN_CONTEXT_USER_NIX = "USER_NIX";
-       private final static String LOGIN_CONTEXT_USER_NT = "USER_NT";
-
-       public static String getOsUsername() {
-               return System.getProperty("user.name");
-       }
-
-       public static LoginContext loginAsSystemUser(Subject subject) {
-               try {
-                       URL jaasConfigurationUrl = OsUserUtils.class.getClassLoader()
-                                       .getResource("org/argeo/osgi/useradmin/jaas-os.cfg");
-                       URIParameter uriParameter = new URIParameter(jaasConfigurationUrl.toURI());
-                       Configuration jaasConfiguration = Configuration.getInstance("JavaLoginConfig", uriParameter);
-                       LoginContext lc = new LoginContext(isWindows() ? LOGIN_CONTEXT_USER_NT : LOGIN_CONTEXT_USER_NIX, subject,
-                                       null, jaasConfiguration);
-                       lc.login();
-                       return lc;
-               } catch (URISyntaxException | NoSuchAlgorithmException | LoginException e) {
-                       throw new RuntimeException("Cannot login as system user", e);
-               }
-       }
-
-       public static void main(String args[]) {
-               Subject subject = new Subject();
-               LoginContext loginContext = loginAsSystemUser(subject);
-               System.out.println(subject);
-               try {
-                       loginContext.logout();
-               } catch (LoginException e) {
-                       // silent
-               }
-       }
-
-       private static boolean isWindows() {
-               return System.getProperty("os.name").startsWith("Windows");
-       }
-
-       private OsUserUtils() {
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/TokenUtils.java b/org.argeo.util/src/org/argeo/osgi/useradmin/TokenUtils.java
deleted file mode 100644 (file)
index 178b4ae..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.util.naming.LdapAttrs.description;
-import static org.argeo.util.naming.LdapAttrs.owner;
-
-import java.security.Principal;
-import java.time.Instant;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.security.auth.Subject;
-
-import org.argeo.util.naming.NamingUtils;
-import org.osgi.service.useradmin.Group;
-
-/**
- * Canonically implements the Argeo token conventions.
- */
-public class TokenUtils {
-       public static Set<String> tokensUsed(Subject subject, String tokensBaseDn) {
-               Set<String> res = new HashSet<>();
-               for (Principal principal : subject.getPrincipals()) {
-                       String name = principal.getName();
-                       if (name.endsWith(tokensBaseDn)) {
-                               try {
-                                       LdapName ldapName = new LdapName(name);
-                                       String token = ldapName.getRdn(ldapName.size()).getValue().toString();
-                                       res.add(token);
-                               } catch (InvalidNameException e) {
-                                       throw new IllegalArgumentException("Invalid principal " + principal, e);
-                               }
-                       }
-               }
-               return res;
-       }
-
-       /** The user related to this token group */
-       public static String userDn(Group tokenGroup) {
-               return (String) tokenGroup.getProperties().get(owner.name());
-       }
-
-       public static boolean isExpired(Group tokenGroup) {
-               return isExpired(tokenGroup, Instant.now());
-
-       }
-
-       public static boolean isExpired(Group tokenGroup, Instant instant) {
-               String expiryDateStr = (String) tokenGroup.getProperties().get(description.name());
-               if (expiryDateStr != null) {
-                       Instant expiryDate = NamingUtils.ldapDateToInstant(expiryDateStr);
-                       if (expiryDate.isBefore(instant)) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-//     private final String token;
-//
-//     public TokenUtils(String token) {
-//             this.token = token;
-//     }
-//
-//     public String getToken() {
-//             return token;
-//     }
-//
-//     @Override
-//     public int hashCode() {
-//             return token.hashCode();
-//     }
-//
-//     @Override
-//     public boolean equals(Object obj) {
-//             if ((obj instanceof TokenUtils) && ((TokenUtils) obj).token.equals(token))
-//                     return true;
-//             return false;
-//     }
-//
-//     @Override
-//     public String toString() {
-//             return "Token #" + hashCode();
-//     }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java
deleted file mode 100644 (file)
index 05ed7cf..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import org.argeo.util.directory.Directory;
-import org.argeo.util.directory.HierarchyUnit;
-import org.osgi.service.useradmin.Role;
-
-/** Information about a user directory. */
-public interface UserDirectory extends Directory {
-
-       HierarchyUnit getHierarchyUnit(Role role);
-
-       Iterable<? extends Role> getHierarchyUnitRoles(HierarchyUnit hierarchyUnit, String filter, boolean deep);
-
-       String getRolePath(Role role);
-
-       String getRoleSimpleName(Role role);
-
-       Role getRoleByPath(String path);
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/jaas-os.cfg b/org.argeo.util/src/org/argeo/osgi/useradmin/jaas-os.cfg
deleted file mode 100644 (file)
index da04505..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-USER_NIX {
-    com.sun.security.auth.module.UnixLoginModule requisite; 
-};
-
-USER_NT {
-    com.sun.security.auth.module.NTLoginModule requisite; 
-};
-
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/package-info.java b/org.argeo.util/src/org/argeo/osgi/useradmin/package-info.java
deleted file mode 100644 (file)
index c108d2c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** LDAP and LDIF based OSGi useradmin implementation. */
-package org.argeo.osgi.useradmin;
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/osgi/util/FilterRequirement.java b/org.argeo.util/src/org/argeo/osgi/util/FilterRequirement.java
deleted file mode 100644 (file)
index 31f1d4d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.argeo.osgi.util;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.osgi.resource.Namespace;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-
-/** Simplify filtering resources. */
-public class FilterRequirement implements Requirement {
-       private String namespace;
-       private String filter;
-
-       public FilterRequirement(String namespace, String filter) {
-               this.namespace = namespace;
-               this.filter = filter;
-       }
-
-       @Override
-       public Resource getResource() {
-               return null;
-       }
-
-       @Override
-       public String getNamespace() {
-               return namespace;
-       }
-
-       @Override
-       public Map<String, String> getDirectives() {
-               Map<String, String> directives = new HashMap<>();
-               directives.put(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter);
-               return directives;
-       }
-
-       @Override
-       public Map<String, Object> getAttributes() {
-               return new HashMap<>();
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/util/OnServiceRegistration.java b/org.argeo.util/src/org/argeo/osgi/util/OnServiceRegistration.java
deleted file mode 100644 (file)
index 5a6760e..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.argeo.osgi.util;
-
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.function.Function;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class OnServiceRegistration<R> implements Future<R> {
-       private BundleContext ownBundleContext = FrameworkUtil.getBundle(OnServiceRegistration.class).getBundleContext();
-
-       private ServiceTracker<?, ?> st;
-
-       private R result;
-       private boolean cancelled = false;
-       private Throwable exception;
-
-       public <T> OnServiceRegistration(Class<T> clss, Function<T, R> function) {
-               this(null, clss, function);
-       }
-
-       public <T> OnServiceRegistration(BundleContext bundleContext, Class<T> clss, Function<T, R> function) {
-               st = new ServiceTracker<T, T>(bundleContext != null ? bundleContext : ownBundleContext, clss, null) {
-
-                       @Override
-                       public T addingService(ServiceReference<T> reference) {
-                               T service = super.addingService(reference);
-                               try {
-                                       if (result != null)// we only want the first one
-                                               return service;
-                                       result = function.apply(service);
-                                       return service;
-                               } catch (Exception e) {
-                                       exception = e;
-                                       return service;
-                               } finally {
-                                       close();
-                               }
-                       }
-               };
-               st.open(bundleContext == null);
-       }
-
-       @Override
-       public boolean cancel(boolean mayInterruptIfRunning) {
-               if (result != null || exception != null || cancelled)
-                       return false;
-               st.close();
-               cancelled = true;
-               return true;
-       }
-
-       @Override
-       public boolean isCancelled() {
-               return cancelled;
-       }
-
-       @Override
-       public boolean isDone() {
-               return result != null || cancelled;
-       }
-
-       @Override
-       public R get() throws InterruptedException, ExecutionException {
-               st.waitForService(0);
-               return tryGetResult();
-       }
-
-       @Override
-       public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
-               st.waitForService(TimeUnit.MILLISECONDS.convert(timeout, unit));
-               if (result == null)
-                       throw new TimeoutException("No result after " + timeout + " " + unit);
-               return tryGetResult();
-       }
-
-       protected R tryGetResult() throws ExecutionException, CancellationException {
-               if (cancelled)
-                       throw new CancellationException();
-               if (exception != null)
-                       throw new ExecutionException(exception);
-               if (result == null)// this should not happen
-                       try {
-                               throw new IllegalStateException("No result available");
-                       } catch (Exception e) {
-                               exception = e;
-                               throw new ExecutionException(e);
-                       }
-               return result;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/util/OsgiRegister.java b/org.argeo.util/src/org/argeo/osgi/util/OsgiRegister.java
deleted file mode 100644 (file)
index 5728b90..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.argeo.osgi.util;
-
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ForkJoinPool;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-public class OsgiRegister {
-       private final BundleContext bundleContext;
-       private Executor executor;
-
-       private CompletableFuture<Void> shutdownStarting = new CompletableFuture<Void>();
-
-       public OsgiRegister(BundleContext bundleContext) {
-               this.bundleContext = bundleContext;
-               // TODO experiment with dedicated executors
-               this.executor = ForkJoinPool.commonPool();
-       }
-
-       public <T> void set(T obj, Class<T> clss, Map<String, Object> attributes, Class<?>... classes) {
-               CompletableFuture<ServiceRegistration<?>> srf = new CompletableFuture<ServiceRegistration<?>>();
-               CompletableFuture<T> postRegistration = CompletableFuture.supplyAsync(() -> {
-                       List<String> lst = new ArrayList<>();
-                       lst.add(clss.getName());
-                       for (Class<?> c : classes) {
-                               lst.add(c.getName());
-                       }
-                       ServiceRegistration<?> sr = bundleContext.registerService(lst.toArray(new String[lst.size()]), obj,
-                                       new Hashtable<String, Object>(attributes));
-                       srf.complete(sr);
-                       return obj;
-               }, executor);
-//             Singleton<T> singleton = new Singleton<T>(clss, postRegistration);
-
-//             shutdownStarting. //
-//                             thenCompose(singleton::prepareUnregistration). //
-//                             thenRunAsync(() -> {
-//                                     try {
-//                                             srf.get().unregister();
-//                                     } catch (InterruptedException | ExecutionException e) {
-//                                             e.printStackTrace();
-//                                     }
-//                             }, executor);
-//             return singleton;
-       }
-
-       public void shutdown() {
-               shutdownStarting.complete(null);
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/CompositeString.java b/org.argeo.util/src/org/argeo/util/CompositeString.java
deleted file mode 100644 (file)
index 2f8587d..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-package org.argeo.util;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.StringTokenizer;
-
-/** A name that can be expressed with various conventions. */
-public class CompositeString {
-       public final static Character UNDERSCORE = Character.valueOf('_');
-       public final static Character SPACE = Character.valueOf(' ');
-       public final static Character DASH = Character.valueOf('-');
-
-       private final String[] parts;
-
-       // optimisation
-       private final int hashCode;
-
-       public CompositeString(String str) {
-               Objects.requireNonNull(str, "String cannot be null");
-               if ("".equals(str.trim()))
-                       throw new IllegalArgumentException("String cannot be empty");
-               if (!str.equals(str.trim()))
-                       throw new IllegalArgumentException("String must be trimmed");
-               this.parts = toParts(str);
-               hashCode = hashCode(this.parts);
-       }
-
-       public String toString(char separator, boolean upperCase) {
-               StringBuilder sb = null;
-               for (String part : parts) {
-                       if (sb == null) {
-                               sb = new StringBuilder();
-                       } else {
-                               sb.append(separator);
-                       }
-                       sb.append(upperCase ? part.toUpperCase() : part);
-               }
-               return sb.toString();
-       }
-
-       public String toStringCaml(boolean firstCharUpperCase) {
-               StringBuilder sb = null;
-               for (String part : parts) {
-                       if (sb == null) {// first
-                               sb = new StringBuilder();
-                               sb.append(firstCharUpperCase ? Character.toUpperCase(part.charAt(0)) : part.charAt(0));
-                       } else {
-                               sb.append(Character.toUpperCase(part.charAt(0)));
-                       }
-
-                       if (part.length() > 1)
-                               sb.append(part.substring(1));
-               }
-               return sb.toString();
-       }
-
-       @Override
-       public int hashCode() {
-               return hashCode;
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj == null || !(obj instanceof CompositeString))
-                       return false;
-
-               CompositeString other = (CompositeString) obj;
-               return Arrays.equals(parts, other.parts);
-       }
-
-       @Override
-       public String toString() {
-               return toString(DASH, false);
-       }
-
-       public static String[] toParts(String str) {
-               Character separator = null;
-               if (str.indexOf(UNDERSCORE) >= 0) {
-                       checkNo(str, SPACE);
-                       checkNo(str, DASH);
-                       separator = UNDERSCORE;
-               } else if (str.indexOf(DASH) >= 0) {
-                       checkNo(str, SPACE);
-                       checkNo(str, UNDERSCORE);
-                       separator = DASH;
-               } else if (str.indexOf(SPACE) >= 0) {
-                       checkNo(str, DASH);
-                       checkNo(str, UNDERSCORE);
-                       separator = SPACE;
-               }
-
-               List<String> res = new ArrayList<>();
-               if (separator != null) {
-                       StringTokenizer st = new StringTokenizer(str, separator.toString());
-                       while (st.hasMoreTokens()) {
-                               res.add(st.nextToken().toLowerCase());
-                       }
-               } else {
-                       // single
-                       String strLowerCase = str.toLowerCase();
-                       if (str.toUpperCase().equals(str) || strLowerCase.equals(str))
-                               return new String[] { strLowerCase };
-
-                       // CAML
-                       StringBuilder current = null;
-                       for (char c : str.toCharArray()) {
-                               if (Character.isUpperCase(c)) {
-                                       if (current != null)
-                                               res.add(current.toString());
-                                       current = new StringBuilder();
-                               }
-                               if (current == null)// first char is lower case
-                                       current = new StringBuilder();
-                               current.append(Character.toLowerCase(c));
-                       }
-                       res.add(current.toString());
-               }
-               return res.toArray(new String[res.size()]);
-       }
-
-       private static void checkNo(String str, Character c) {
-               if (str.indexOf(c) >= 0) {
-                       throw new IllegalArgumentException("Only one kind of sperator is allowed");
-               }
-       }
-
-       private static int hashCode(String[] parts) {
-               int hashCode = 0;
-               for (String part : parts) {
-                       hashCode = hashCode + part.hashCode();
-               }
-               return hashCode;
-       }
-
-       static boolean smokeTests() {
-               CompositeString plainName = new CompositeString("NAME");
-               assert "name".equals(plainName.toString());
-               assert "NAME".equals(plainName.toString(UNDERSCORE, true));
-               assert "name".equals(plainName.toString(UNDERSCORE, false));
-               assert "name".equals(plainName.toStringCaml(false));
-               assert "Name".equals(plainName.toStringCaml(true));
-
-               CompositeString camlName = new CompositeString("myComplexName");
-
-               assert new CompositeString("my-complex-name").equals(camlName);
-               assert new CompositeString("MY_COMPLEX_NAME").equals(camlName);
-               assert new CompositeString("My complex Name").equals(camlName);
-               assert new CompositeString("MyComplexName").equals(camlName);
-
-               assert "my-complex-name".equals(camlName.toString());
-               assert "MY_COMPLEX_NAME".equals(camlName.toString(UNDERSCORE, true));
-               assert "my_complex_name".equals(camlName.toString(UNDERSCORE, false));
-               assert "myComplexName".equals(camlName.toStringCaml(false));
-               assert "MyComplexName".equals(camlName.toStringCaml(true));
-
-               return CompositeString.class.desiredAssertionStatus();
-       }
-
-       public static void main(String[] args) {
-               System.out.println(smokeTests());
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/CsvParser.java b/org.argeo.util/src/org/argeo/util/CsvParser.java
deleted file mode 100644 (file)
index b903f77..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-package org.argeo.util;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Parses a CSV file interpreting the first line as a header. The
- * {@link #parse(InputStream)} method and the setters are synchronized so that
- * the object cannot be modified when parsing.
- */
-public abstract class CsvParser {
-       private char separator = ',';
-       private char quote = '\"';
-
-       private Boolean noHeader = false;
-       private Boolean strictLineAsLongAsHeader = true;
-
-       /**
-        * Actually process a parsed line. If
-        * {@link #setStrictLineAsLongAsHeader(Boolean)} is true (default) the header
-        * and the tokens are guaranteed to have the same size.
-        * 
-        * @param lineNumber the current line number, starts at 1 (the header, if header
-        *                   processing is enabled, the first line otherwise)
-        * @param header     the read-only header or null if
-        *                   {@link #setNoHeader(Boolean)} is true (default is false)
-        * @param tokens     the parsed tokens
-        */
-       protected abstract void processLine(Integer lineNumber, List<String> header, List<String> tokens);
-
-       /**
-        * Parses the CSV file (stream is closed at the end)
-        * 
-        * @param in the stream to parse
-        * 
-        * @deprecated Use {@link #parse(InputStream, Charset)} instead.
-        */
-       @Deprecated
-       public synchronized void parse(InputStream in) {
-               parse(in, (Charset) null);
-       }
-
-       /**
-        * Parses the CSV file (stream is closed at the end)
-        * 
-        * @param in       the stream to parse
-        * @param encoding the encoding to use.
-        * 
-        * @deprecated Use {@link #parse(InputStream, Charset)} instead.
-        */
-       @Deprecated
-       public synchronized void parse(InputStream in, String encoding) {
-               Reader reader;
-               if (encoding == null)
-                       reader = new InputStreamReader(in);
-               else
-                       try {
-                               reader = new InputStreamReader(in, encoding);
-                       } catch (UnsupportedEncodingException e) {
-                               throw new IllegalArgumentException(e);
-                       }
-               parse(reader);
-       }
-
-       /**
-        * Parses the CSV file (stream is closed at the end)
-        * 
-        * @param in      the stream to parse
-        * @param charset the charset to use
-        */
-       public synchronized void parse(InputStream in, Charset charset) {
-               Reader reader;
-               if (charset == null)
-                       reader = new InputStreamReader(in);
-               else
-                       reader = new InputStreamReader(in, charset);
-               parse(reader);
-       }
-
-       /**
-        * Parses the CSV file (stream is closed at the end)
-        * 
-        * @param reader the reader to use (it will be buffered)
-        */
-       public synchronized void parse(Reader reader) {
-               Integer lineCount = 0;
-               try (BufferedReader bufferedReader = new BufferedReader(reader)) {
-                       List<String> header = null;
-                       if (!noHeader) {
-                               String headerStr = bufferedReader.readLine();
-                               if (headerStr == null)// empty file
-                                       return;
-                               lineCount++;
-                               header = new ArrayList<String>();
-                               StringBuffer currStr = new StringBuffer("");
-                               Boolean wasInquote = false;
-                               while (parseLine(headerStr, header, currStr, wasInquote)) {
-                                       headerStr = bufferedReader.readLine();
-                                       if (headerStr == null)
-                                               break;
-                                       wasInquote = true;
-                               }
-                               header = Collections.unmodifiableList(header);
-                       }
-
-                       String line = null;
-                       lines: while ((line = bufferedReader.readLine()) != null) {
-                               line = preProcessLine(line);
-                               if (line == null) {
-                                       // skip line
-                                       continue lines;
-                               }
-                               lineCount++;
-                               List<String> tokens = new ArrayList<String>();
-                               StringBuffer currStr = new StringBuffer("");
-                               Boolean wasInquote = false;
-                               sublines: while (parseLine(line, tokens, currStr, wasInquote)) {
-                                       line = bufferedReader.readLine();
-                                       if (line == null)
-                                               break sublines;
-                                       wasInquote = true;
-                               }
-                               if (!noHeader && strictLineAsLongAsHeader) {
-                                       int headerSize = header.size();
-                                       int tokenSize = tokens.size();
-                                       if (tokenSize == 1 && line.trim().equals(""))
-                                               continue lines;// empty line
-                                       if (headerSize != tokenSize) {
-                                               throw new IllegalStateException("Token size " + tokenSize + " is different from header size "
-                                                               + headerSize + " at line " + lineCount + ", line: " + line + ", header: " + header
-                                                               + ", tokens: " + tokens);
-                                       }
-                               }
-                               processLine(lineCount, header, tokens);
-                       }
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot parse CSV file (line: " + lineCount + ")", e);
-               }
-       }
-
-       /**
-        * Called before each (logical) line is processed, giving a change to modify it
-        * (typically for cleaning dirty files). To be overridden, return the line
-        * unchanged by default. Skip the line if 'null' is returned.
-        */
-       protected String preProcessLine(String line) {
-               return line;
-       }
-
-       /**
-        * Parses a line character by character for performance purpose
-        * 
-        * @return whether to continue parsing this line
-        */
-       protected Boolean parseLine(String str, List<String> tokens, StringBuffer currStr, Boolean wasInquote) {
-               if (wasInquote)
-                       currStr.append('\n');
-
-               char[] arr = str.toCharArray();
-               boolean inQuote = wasInquote;
-               for (int i = 0; i < arr.length; i++) {
-                       char c = arr[i];
-                       if (c == separator) {
-                               if (!inQuote) {
-                                       tokens.add(currStr.toString());
-//                                     currStr.delete(0, currStr.length());
-                                       currStr.setLength(0);
-                                       currStr.trimToSize();
-                               } else {
-                                       // we don't remove separator that are in a quoted substring
-                                       // System.out
-                                       // .println("IN QUOTE, got a separator: [" + c + "]");
-                                       currStr.append(c);
-                               }
-                       } else if (c == quote) {
-                               if (inQuote && (i + 1) < arr.length && arr[i + 1] == quote) {
-                                       // case of double quote
-                                       currStr.append(quote);
-                                       i++;
-                               } else {// standard
-                                       inQuote = inQuote ? false : true;
-                               }
-                       } else {
-                               currStr.append(c);
-                       }
-               }
-
-               if (!inQuote) {
-                       tokens.add(currStr.toString());
-                       // System.out.println("# TOKEN: " + currStr);
-               }
-               // if (inQuote)
-               // throw new ArgeoException("Missing quote at the end of the line "
-               // + str + " (parsed: " + tokens + ")");
-               if (inQuote)
-                       return true;
-               else
-                       return false;
-               // return tokens;
-       }
-
-       public char getSeparator() {
-               return separator;
-       }
-
-       public synchronized void setSeparator(char separator) {
-               this.separator = separator;
-       }
-
-       public char getQuote() {
-               return quote;
-       }
-
-       public synchronized void setQuote(char quote) {
-               this.quote = quote;
-       }
-
-       public Boolean getNoHeader() {
-               return noHeader;
-       }
-
-       public synchronized void setNoHeader(Boolean noHeader) {
-               this.noHeader = noHeader;
-       }
-
-       public Boolean getStrictLineAsLongAsHeader() {
-               return strictLineAsLongAsHeader;
-       }
-
-       public synchronized void setStrictLineAsLongAsHeader(Boolean strictLineAsLongAsHeader) {
-               this.strictLineAsLongAsHeader = strictLineAsLongAsHeader;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java b/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java
deleted file mode 100644 (file)
index 8eb6e94..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.util;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * CSV parser allowing to process lines as maps whose keys are the header
- * fields.
- */
-public abstract class CsvParserWithLinesAsMap extends CsvParser {
-
-       /**
-        * Actually processes a line.
-        * 
-        * @param lineNumber the current line number, starts at 1 (the header, if header
-        *                   processing is enabled, the first lien otherwise)
-        * @param line       the parsed tokens as a map whose keys are the header fields
-        */
-       protected abstract void processLine(Integer lineNumber, Map<String, String> line);
-
-       protected final void processLine(Integer lineNumber, List<String> header, List<String> tokens) {
-               if (header == null)
-                       throw new IllegalArgumentException("Only CSV with header is supported");
-               Map<String, String> line = new HashMap<String, String>();
-               for (int i = 0; i < header.size(); i++) {
-                       String key = header.get(i);
-                       String value = null;
-                       if (i < tokens.size())
-                               value = tokens.get(i);
-                       line.put(key, value);
-               }
-               processLine(lineNumber, line);
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/CsvWriter.java b/org.argeo.util/src/org/argeo/util/CsvWriter.java
deleted file mode 100644 (file)
index c3b3a3a..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-package org.argeo.util;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.Iterator;
-import java.util.List;
-
-/** Write in CSV format. */
-public class CsvWriter {
-       private final Writer out;
-
-       private char separator = ',';
-       private char quote = '\"';
-
-       /**
-        * Creates a CSV writer.
-        * 
-        * @param out the stream to write to. Caller is responsible for closing it.
-        * 
-        * @deprecated Use {@link #CsvWriter(OutputStream, Charset)} instead.
-        * 
-        */
-       @Deprecated
-       public CsvWriter(OutputStream out) {
-               this.out = new OutputStreamWriter(out);
-       }
-
-       /**
-        * Creates a CSV writer.
-        * 
-        * @param out      the stream to write to. Caller is responsible for closing it.
-        * @param encoding the encoding to use.
-        * 
-        * @deprecated Use {@link #CsvWriter(OutputStream, Charset)} instead.
-        */
-       @Deprecated
-       public CsvWriter(OutputStream out, String encoding) {
-               try {
-                       this.out = new OutputStreamWriter(out, encoding);
-               } catch (UnsupportedEncodingException e) {
-                       throw new IllegalArgumentException(e);
-               }
-       }
-
-       /**
-        * Creates a CSV writer.
-        * 
-        * @param out     the stream to write to. Caller is responsible for closing it.
-        * @param charset the charset to use
-        */
-       public CsvWriter(OutputStream out, Charset charset) {
-               this.out = new OutputStreamWriter(out, charset);
-       }
-
-       /**
-        * Creates a CSV writer.
-        * 
-        * @param out the stream to write to. Caller is responsible for closing it.
-        */
-       public CsvWriter(Writer writer) {
-               this.out = writer;
-       }
-
-       /**
-        * Write a CSV line. Also used to write a header if needed (this is transparent
-        * for the CSV writer): simply call it first, before writing the lines.
-        */
-       public void writeLine(List<?> tokens) {
-               try {
-                       Iterator<?> it = tokens.iterator();
-                       while (it.hasNext()) {
-                               Object obj = it.next();
-                               writeToken(obj != null ? obj.toString() : null);
-                               if (it.hasNext())
-                                       out.write(separator);
-                       }
-                       out.write('\n');
-                       out.flush();
-               } catch (IOException e) {
-                       throw new RuntimeException("Could not write " + tokens, e);
-               }
-       }
-
-       /**
-        * Write a CSV line. Also used to write a header if needed (this is transparent
-        * for the CSV writer): simply call it first, before writing the lines.
-        */
-       public void writeLine(Object[] tokens) {
-               try {
-                       for (int i = 0; i < tokens.length; i++) {
-                               if (tokens[i] == null) {
-                                       writeToken(null);
-                               } else {
-                                       writeToken(tokens[i].toString());
-                               }
-                               if (i != (tokens.length - 1))
-                                       out.write(separator);
-                       }
-                       out.write('\n');
-                       out.flush();
-               } catch (IOException e) {
-                       throw new RuntimeException("Could not write " + tokens, e);
-               }
-       }
-
-       protected void writeToken(String token) throws IOException {
-               if (token == null) {
-                       // TODO configure how to deal with null
-                       out.write("");
-                       return;
-               }
-               // +2 for possible quotes, another +2 assuming there would be an already
-               // quoted string where quotes needs to be duplicated
-               // another +2 for safety
-               // we don't want to increase buffer size while writing
-               StringBuffer buf = new StringBuffer(token.length() + 6);
-               char[] arr = token.toCharArray();
-               boolean shouldQuote = false;
-               for (char c : arr) {
-                       if (!shouldQuote) {
-                               if (c == separator)
-                                       shouldQuote = true;
-                               if (c == '\n')
-                                       shouldQuote = true;
-                       }
-
-                       if (c == quote) {
-                               shouldQuote = true;
-                               // duplicate quote
-                               buf.append(quote);
-                       }
-
-                       // generic case
-                       buf.append(c);
-               }
-
-               if (shouldQuote == true)
-                       out.write(quote);
-               out.write(buf.toString());
-               if (shouldQuote == true)
-                       out.write(quote);
-       }
-
-       public void setSeparator(char separator) {
-               this.separator = separator;
-       }
-
-       public void setQuote(char quote) {
-               this.quote = quote;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/CurrentSubject.java b/org.argeo.util/src/org/argeo/util/CurrentSubject.java
deleted file mode 100644 (file)
index 60ce3cf..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.argeo.util;
-
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CompletionException;
-
-import javax.security.auth.Subject;
-
-/**
- * Prepare evolution of Java APIs introduced in JDK 18, as these static methods
- * will be added to {@link Subject}.
- */
-@SuppressWarnings("removal")
-public class CurrentSubject {
-
-       private final static boolean useThreadLocal = Boolean
-                       .parseBoolean(System.getProperty("jdk.security.auth.subject.useTL"));
-
-       private final static InheritableThreadLocal<Subject> current = new InheritableThreadLocal<>();
-
-       public static Subject current() {
-               if (useThreadLocal) {
-                       return current.get();
-               } else {// legacy
-                       Subject subject = Subject.getSubject(AccessController.getContext());
-                       return subject;
-               }
-       }
-
-       public static <T> T callAs(Subject subject, Callable<T> action) {
-               if (useThreadLocal) {
-                       Subject previous = current();
-                       current.set(subject);
-                       try {
-                               return action.call();
-                       } catch (Exception e) {
-                               throw new CompletionException("Failed to execute action for " + subject, e);
-                       } finally {
-                               current.set(previous);
-                       }
-               } else {// legacy
-                       try {
-                               return Subject.doAs(subject, new PrivilegedExceptionAction<T>() {
-
-                                       @Override
-                                       public T run() throws Exception {
-                                               return action.call();
-                                       }
-
-                               });
-                       } catch (PrivilegedActionException e) {
-                               throw new CompletionException("Failed to execute action for " + subject, e.getCause());
-                       } catch (Exception e) {
-                               throw new CompletionException("Failed to execute action for " + subject, e);
-                       }
-               }
-       }
-
-       /** Singleton. */
-       private CurrentSubject() {
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/DictionaryKeys.java b/org.argeo.util/src/org/argeo/util/DictionaryKeys.java
deleted file mode 100644 (file)
index d17c86f..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.argeo.util;
-
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Iterator;
-
-/**
- * Access the keys of a {@link String}-keyed {@link Dictionary} (common throughout
- * the OSGi APIs) as an {@link Iterable} so that they are easily usable in
- * for-each loops.
- */
-class DictionaryKeys implements Iterable<String> {
-       private final Dictionary<String, ?> dictionary;
-
-       public DictionaryKeys(Dictionary<String, ?> dictionary) {
-               this.dictionary = dictionary;
-       }
-
-       @Override
-       public Iterator<String> iterator() {
-               return new KeyIterator(dictionary.keys());
-       }
-
-       private static class KeyIterator implements Iterator<String> {
-               private final Enumeration<String> keys;
-
-               KeyIterator(Enumeration<String> keys) {
-                       this.keys = keys;
-               }
-
-               @Override
-               public boolean hasNext() {
-                       return keys.hasMoreElements();
-               }
-
-               @Override
-               public String next() {
-                       return keys.nextElement();
-               }
-
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/DigestUtils.java b/org.argeo.util/src/org/argeo/util/DigestUtils.java
deleted file mode 100644 (file)
index 38b4e70..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-package org.argeo.util;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileChannel.MapMode;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-/** Utilities around cryptographic digests */
-public class DigestUtils {
-       public final static String MD5 = "MD5";
-       public final static String SHA1 = "SHA1";
-       public final static String SHA256 = "SHA-256";
-       public final static String SHA512 = "SHA-512";
-
-       private static Boolean debug = false;
-       // TODO: make it configurable
-       private final static Integer byteBufferCapacity = 100 * 1024;// 100 KB
-
-       public static byte[] sha1(byte[]... bytes) {
-               try {
-                       MessageDigest digest = MessageDigest.getInstance(SHA1);
-                       for (byte[] arr : bytes)
-                               digest.update(arr);
-                       byte[] checksum = digest.digest();
-                       return checksum;
-               } catch (NoSuchAlgorithmException e) {
-                       throw new UnsupportedOperationException("SHA1 is not avalaible", e);
-               }
-       }
-
-       public static byte[] digestAsBytes(String algorithm, byte[]... bytes) {
-               try {
-                       MessageDigest digest = MessageDigest.getInstance(algorithm);
-                       for (byte[] arr : bytes)
-                               digest.update(arr);
-                       byte[] checksum = digest.digest();
-                       return checksum;
-               } catch (NoSuchAlgorithmException e) {
-                       throw new UnsupportedOperationException("Cannot digest with algorithm " + algorithm, e);
-               }
-       }
-
-       public static String digest(String algorithm, byte[]... bytes) {
-               return toHexString(digestAsBytes(algorithm, bytes));
-       }
-
-       public static String digest(String algorithm, InputStream in) {
-               try {
-                       MessageDigest digest = MessageDigest.getInstance(algorithm);
-                       // ReadableByteChannel channel = Channels.newChannel(in);
-                       // ByteBuffer bb = ByteBuffer.allocateDirect(byteBufferCapacity);
-                       // while (channel.read(bb) > 0)
-                       // digest.update(bb);
-                       byte[] buffer = new byte[byteBufferCapacity];
-                       int read = 0;
-                       while ((read = in.read(buffer)) > 0) {
-                               digest.update(buffer, 0, read);
-                       }
-
-                       byte[] checksum = digest.digest();
-                       String res = toHexString(checksum);
-                       return res;
-               } catch (NoSuchAlgorithmException e) {
-                       throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e);
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               } finally {
-                       StreamUtils.closeQuietly(in);
-               }
-       }
-
-       public static String digest(String algorithm, File file) {
-               FileInputStream fis = null;
-               FileChannel fc = null;
-               try {
-                       fis = new FileInputStream(file);
-                       fc = fis.getChannel();
-
-                       // Get the file's size and then map it into memory
-                       int sz = (int) fc.size();
-                       ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz);
-                       return digest(algorithm, bb);
-               } catch (IOException e) {
-                       throw new IllegalArgumentException("Cannot digest " + file + " with algorithm " + algorithm, e);
-               } finally {
-                       StreamUtils.closeQuietly(fis);
-                       if (fc.isOpen())
-                               try {
-                                       fc.close();
-                               } catch (IOException e) {
-                                       // silent
-                               }
-               }
-       }
-
-       protected static String digest(String algorithm, ByteBuffer bb) {
-               long begin = System.currentTimeMillis();
-               try {
-                       MessageDigest digest = MessageDigest.getInstance(algorithm);
-                       digest.update(bb);
-                       byte[] checksum = digest.digest();
-                       String res = toHexString(checksum);
-                       long end = System.currentTimeMillis();
-                       if (debug)
-                               System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
-                       return res;
-               } catch (NoSuchAlgorithmException e) {
-                       throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e);
-               }
-       }
-
-       public static String sha1hex(Path path) {
-               return digest(SHA1, path, byteBufferCapacity);
-       }
-
-       public static String digest(String algorithm, Path path, long bufferSize) {
-               byte[] digest = digestAsBytes(algorithm, path, bufferSize);
-               return toHexString(digest);
-       }
-
-       public static byte[] digestAsBytes(String algorithm, Path file, long bufferSize) {
-               long begin = System.currentTimeMillis();
-               try {
-                       MessageDigest md = MessageDigest.getInstance(algorithm);
-                       FileChannel fc = FileChannel.open(file);
-                       long fileSize = Files.size(file);
-                       if (fileSize <= bufferSize) {
-                               ByteBuffer bb = fc.map(MapMode.READ_ONLY, 0, fileSize);
-                               md.update(bb);
-                       } else {
-                               long lastCycle = (fileSize / bufferSize) - 1;
-                               long position = 0;
-                               for (int i = 0; i <= lastCycle; i++) {
-                                       ByteBuffer bb;
-                                       if (i != lastCycle) {
-                                               bb = fc.map(MapMode.READ_ONLY, position, bufferSize);
-                                               position = position + bufferSize;
-                                       } else {
-                                               bb = fc.map(MapMode.READ_ONLY, position, fileSize - position);
-                                               position = fileSize;
-                                       }
-                                       md.update(bb);
-                               }
-                       }
-                       long end = System.currentTimeMillis();
-                       if (debug)
-                               System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s");
-                       return md.digest();
-               } catch (NoSuchAlgorithmException e) {
-                       throw new IllegalArgumentException("Cannot digest " + file + "  with algorithm " + algorithm, e);
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot digest " + file + "  with algorithm " + algorithm, e);
-               }
-       }
-
-       public static void main(String[] args) {
-               File file;
-               if (args.length > 0)
-                       file = new File(args[0]);
-               else {
-                       System.err.println("Usage: <file> [<algorithm>]" + " (see http://java.sun.com/j2se/1.5.0/"
-                                       + "docs/guide/security/CryptoSpec.html#AppA)");
-                       return;
-               }
-
-               if (args.length > 1) {
-                       String algorithm = args[1];
-                       System.out.println(digest(algorithm, file));
-               } else {
-                       String algorithm = "MD5";
-                       System.out.println(algorithm + ": " + digest(algorithm, file));
-                       algorithm = "SHA";
-                       System.out.println(algorithm + ": " + digest(algorithm, file));
-                       System.out.println(algorithm + ": " + sha1hex(file.toPath()));
-                       algorithm = "SHA-256";
-                       System.out.println(algorithm + ": " + digest(algorithm, file));
-                       algorithm = "SHA-512";
-                       System.out.println(algorithm + ": " + digest(algorithm, file));
-               }
-       }
-
-       final private static char[] hexArray = "0123456789abcdef".toCharArray();
-
-       /** Converts a byte array to an hex String. */
-       public static String toHexString(byte[] bytes) {
-               char[] hexChars = new char[bytes.length * 2];
-               for (int j = 0; j < bytes.length; j++) {
-                       int v = bytes[j] & 0xFF;
-                       hexChars[j * 2] = hexArray[v >>> 4];
-                       hexChars[j * 2 + 1] = hexArray[v & 0x0F];
-               }
-               return new String(hexChars);
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/DirH.java b/org.argeo.util/src/org/argeo/util/DirH.java
deleted file mode 100644 (file)
index 013897d..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.argeo.util;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/** Hashes the hashes of the files in a directory. */
-public class DirH {
-
-       private final static Charset charset = Charset.forName("UTF-16");
-       private final static long bufferSize = 200 * 1024 * 1024;
-       private final static String algorithm = "SHA";
-
-       private final static byte EOL = (byte) '\n';
-       private final static byte SPACE = (byte) ' ';
-
-       private final int hashSize;
-
-       private final byte[][] hashes;
-       private final byte[][] fileNames;
-       private final byte[] digest;
-       private final byte[] dirName;
-
-       /**
-        * @param dirName can be null or empty
-        */
-       private DirH(byte[][] hashes, byte[][] fileNames, byte[] dirName) {
-               if (hashes.length != fileNames.length)
-                       throw new IllegalArgumentException(hashes.length + " hashes and " + fileNames.length + " file names");
-               this.hashes = hashes;
-               this.fileNames = fileNames;
-               this.dirName = dirName == null ? new byte[0] : dirName;
-               if (hashes.length == 0) {// empty dir
-                       hashSize = 20;
-                       // FIXME what is the digest of an empty dir?
-                       digest = new byte[hashSize];
-                       Arrays.fill(digest, SPACE);
-                       return;
-               }
-               hashSize = hashes[0].length;
-               for (int i = 0; i < hashes.length; i++) {
-                       if (hashes[i].length != hashSize)
-                               throw new IllegalArgumentException(
-                                               "Hash size for " + new String(fileNames[i], charset) + " is " + hashes[i].length);
-               }
-
-               try {
-                       MessageDigest md = MessageDigest.getInstance(algorithm);
-                       for (int i = 0; i < hashes.length; i++) {
-                               md.update(this.hashes[i]);
-                               md.update(SPACE);
-                               md.update(this.fileNames[i]);
-                               md.update(EOL);
-                       }
-                       digest = md.digest();
-               } catch (NoSuchAlgorithmException e) {
-                       throw new IllegalArgumentException("Cannot digest", e);
-               }
-       }
-
-       public void print(PrintStream out) {
-               out.print(DigestUtils.toHexString(digest));
-               if (dirName.length > 0) {
-                       out.print(' ');
-                       out.print(new String(dirName, charset));
-               }
-               out.print('\n');
-               for (int i = 0; i < hashes.length; i++) {
-                       out.print(DigestUtils.toHexString(hashes[i]));
-                       out.print(' ');
-                       out.print(new String(fileNames[i], charset));
-                       out.print('\n');
-               }
-       }
-
-       public static DirH digest(Path dir) {
-               try (DirectoryStream<Path> files = Files.newDirectoryStream(dir)) {
-                       List<byte[]> hs = new ArrayList<byte[]>();
-                       List<String> fNames = new ArrayList<>();
-                       for (Path file : files) {
-                               if (!Files.isDirectory(file)) {
-                                       byte[] digest = DigestUtils.digestAsBytes(algorithm, file, bufferSize);
-                                       hs.add(digest);
-                                       fNames.add(file.getFileName().toString());
-                               }
-                       }
-
-                       byte[][] fileNames = new byte[fNames.size()][];
-                       for (int i = 0; i < fNames.size(); i++) {
-                               fileNames[i] = fNames.get(i).getBytes(charset);
-                       }
-                       byte[][] hashes = hs.toArray(new byte[hs.size()][]);
-                       return new DirH(hashes, fileNames, dir.toString().getBytes(charset));
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot digest " + dir, e);
-               }
-       }
-
-       public static void main(String[] args) {
-               try {
-                       DirH dirH = DirH.digest(Paths.get("/home/mbaudier/tmp/"));
-                       dirH.print(System.out);
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/ExceptionsChain.java b/org.argeo.util/src/org/argeo/util/ExceptionsChain.java
deleted file mode 100644 (file)
index 9f82421..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.argeo.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Serialisable wrapper of a {@link Throwable}. typically to be written as XML
- * or JSON in a server error response.
- */
-public class ExceptionsChain {
-       private List<SystemException> exceptions = new ArrayList<>();
-
-       public ExceptionsChain() {
-       }
-
-       public ExceptionsChain(Throwable exception) {
-               writeException(exception);
-       }
-
-       /** recursive */
-       protected void writeException(Throwable exception) {
-               SystemException systemException = new SystemException(exception);
-               exceptions.add(systemException);
-               Throwable cause = exception.getCause();
-               if (cause != null)
-                       writeException(cause);
-       }
-
-       public List<SystemException> getExceptions() {
-               return exceptions;
-       }
-
-       public void setExceptions(List<SystemException> exceptions) {
-               this.exceptions = exceptions;
-       }
-
-       /** An exception in the chain. */
-       public static class SystemException {
-               private String type;
-               private String message;
-               private List<String> stackTrace;
-
-               public SystemException() {
-               }
-
-               public SystemException(Throwable exception) {
-                       this.type = exception.getClass().getName();
-                       this.message = exception.getMessage();
-                       this.stackTrace = new ArrayList<>();
-                       StackTraceElement[] elems = exception.getStackTrace();
-                       for (int i = 0; i < elems.length; i++)
-                               stackTrace.add("at " + elems[i].toString());
-               }
-
-               public String getType() {
-                       return type;
-               }
-
-               public void setType(String type) {
-                       this.type = type;
-               }
-
-               public String getMessage() {
-                       return message;
-               }
-
-               public void setMessage(String message) {
-                       this.message = message;
-               }
-
-               public List<String> getStackTrace() {
-                       return stackTrace;
-               }
-
-               public void setStackTrace(List<String> stackTrace) {
-                       this.stackTrace = stackTrace;
-               }
-
-               @Override
-               public String toString() {
-                       return "System exception: " + type + ", " + message + ", " + stackTrace;
-               }
-
-       }
-
-       @Override
-       public String toString() {
-               return exceptions.toString();
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/FsUtils.java b/org.argeo.util/src/org/argeo/util/FsUtils.java
deleted file mode 100644 (file)
index cd61b56..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.argeo.util;
-
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-
-/** Utilities around the standard Java file abstractions. */
-public class FsUtils {
-
-       /** Deletes this path, recursively if needed. */
-       public static void copyDirectory(Path source, Path target) {
-               if (!Files.exists(source) || !Files.isDirectory(source))
-                       throw new IllegalArgumentException(source + " is not a directory");
-               if (Files.exists(target) && !Files.isDirectory(target))
-                       throw new IllegalArgumentException(target + " is not a directory");
-               try {
-                       Files.createDirectories(target);
-                       Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
-
-                               @Override
-                               public FileVisitResult preVisitDirectory(Path directory, BasicFileAttributes attrs) throws IOException {
-                                       Path relativePath = source.relativize(directory);
-                                       Path targetDirectory = target.resolve(relativePath);
-                                       if (!Files.exists(targetDirectory))
-                                               Files.createDirectory(targetDirectory);
-                                       return FileVisitResult.CONTINUE;
-                               }
-
-                               @Override
-                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                                       Path relativePath = source.relativize(file);
-                                       Path targetFile = target.resolve(relativePath);
-                                       Files.copy(file, targetFile);
-                                       return FileVisitResult.CONTINUE;
-                               }
-                       });
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot copy " + source + " to " + target, e);
-               }
-
-       }
-
-       /**
-        * Deletes this path, recursively if needed. Does nothing if the path does not
-        * exist.
-        */
-       public static void delete(Path path) {
-               try {
-                       if (!Files.exists(path))
-                               return;
-                       Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
-                               @Override
-                               public FileVisitResult postVisitDirectory(Path directory, IOException e) throws IOException {
-                                       if (e != null)
-                                               throw e;
-                                       Files.delete(directory);
-                                       return FileVisitResult.CONTINUE;
-                               }
-
-                               @Override
-                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                                       Files.delete(file);
-                                       return FileVisitResult.CONTINUE;
-                               }
-                       });
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot delete " + path, e);
-               }
-       }
-
-       /** Singleton. */
-       private FsUtils() {
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/LangUtils.java b/org.argeo.util/src/org/argeo/util/LangUtils.java
deleted file mode 100644 (file)
index 1aee28c..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-package org.argeo.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Writer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoUnit;
-import java.time.temporal.Temporal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-/** Utilities around Java basic features. */
-public class LangUtils {
-       /*
-        * NON-API OSGi
-        */
-       /**
-        * Returns an array with the names of the provided classes. Useful when
-        * registering services with multiple interfaces in OSGi.
-        */
-       public static String[] names(Class<?>... clzz) {
-               String[] res = new String[clzz.length];
-               for (int i = 0; i < clzz.length; i++)
-                       res[i] = clzz[i].getName();
-               return res;
-       }
-
-//     /*
-//      * MAP
-//      */
-//     /**
-//      * Creates a new {@link Map} with one key-value pair. Key should not be null,
-//      * but if the value is null, it returns an empty {@link Map}.
-//      * 
-//      * @deprecated Use {@link Collections#singletonMap(Object, Object)} instead.
-//      */
-//     @Deprecated
-//     public static Map<String, Object> map(String key, Object value) {
-//             assert key != null;
-//             HashMap<String, Object> props = new HashMap<>();
-//             if (value != null)
-//                     props.put(key, value);
-//             return props;
-//     }
-
-       /*
-        * DICTIONARY
-        */
-
-       /**
-        * Creates a new {@link Dictionary} with one key-value pair. Key should not be
-        * null, but if the value is null, it returns an empty {@link Dictionary}.
-        */
-       public static Dictionary<String, Object> dict(String key, Object value) {
-               assert key != null;
-               Hashtable<String, Object> props = new Hashtable<>();
-               if (value != null)
-                       props.put(key, value);
-               return props;
-       }
-
-       /** @deprecated Use {@link #dict(String, Object)} instead. */
-       @Deprecated
-       public static Dictionary<String, Object> dico(String key, Object value) {
-               return dict(key, value);
-       }
-
-       /** Converts a {@link Dictionary} to a {@link Map} of strings. */
-       public static Map<String, String> dictToStringMap(Dictionary<String, ?> properties) {
-               if (properties == null) {
-                       return null;
-               }
-               Map<String, String> res = new HashMap<>(properties.size());
-               Enumeration<String> keys = properties.keys();
-               while (keys.hasMoreElements()) {
-                       String key = keys.nextElement();
-                       res.put(key, properties.get(key).toString());
-               }
-               return res;
-       }
-
-       /** Converts a {@link Dictionary} to a {@link Map}. */
-       public static Map<String, Object> dictToMap(Dictionary<String, ?> properties) {
-               if (properties == null) {
-                       return null;
-               }
-               Map<String, Object> res = new HashMap<>(properties.size());
-               Enumeration<String> keys = properties.keys();
-               while (keys.hasMoreElements()) {
-                       String key = keys.nextElement();
-                       res.put(key, properties.get(key));
-               }
-               return res;
-       }
-
-       /**
-        * Get a string property from this map, expecting to find it, or
-        * <code>null</code> if not found.
-        */
-       public static String get(Map<String, ?> map, String key) {
-               Object res = map.get(key);
-               if (res == null)
-                       return null;
-               return res.toString();
-       }
-
-       /**
-        * Get a string property from this map, expecting to find it.
-        * 
-        * @throws IllegalArgumentException if the key was not found
-        */
-       public static String getNotNull(Map<String, ?> map, String key) {
-               Object res = map.get(key);
-               if (res == null)
-                       throw new IllegalArgumentException("Map " + map + " should contain key " + key);
-               return res.toString();
-       }
-
-       /**
-        * Wraps the keys of the provided {@link Dictionary} as an {@link Iterable}.
-        */
-       public static Iterable<String> keys(Dictionary<String, ?> props) {
-               assert props != null;
-               return new DictionaryKeys(props);
-       }
-
-       static String toJson(Dictionary<String, ?> props) {
-               return toJson(props, false);
-       }
-
-       static String toJson(Dictionary<String, ?> props, boolean pretty) {
-               StringBuilder sb = new StringBuilder();
-               sb.append('{');
-               if (pretty)
-                       sb.append('\n');
-               Enumeration<String> keys = props.keys();
-               while (keys.hasMoreElements()) {
-                       String key = keys.nextElement();
-                       if (pretty)
-                               sb.append(' ');
-                       sb.append('\"').append(key).append('\"');
-                       if (pretty)
-                               sb.append(" : ");
-                       else
-                               sb.append(':');
-                       sb.append('\"').append(props.get(key)).append('\"');
-                       if (keys.hasMoreElements())
-                               sb.append(", ");
-                       if (pretty)
-                               sb.append('\n');
-               }
-               sb.append('}');
-               return sb.toString();
-       }
-
-       static void storeAsProperties(Dictionary<String, Object> props, Path path) throws IOException {
-               if (props == null)
-                       throw new IllegalArgumentException("Props cannot be null");
-               Properties toStore = new Properties();
-               for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
-                       String key = keys.nextElement();
-                       toStore.setProperty(key, props.get(key).toString());
-               }
-               try (OutputStream out = Files.newOutputStream(path)) {
-                       toStore.store(out, null);
-               }
-       }
-
-       static void appendAsLdif(String dnBase, String dnKey, Dictionary<String, Object> props, Path path)
-                       throws IOException {
-               if (props == null)
-                       throw new IllegalArgumentException("Props cannot be null");
-               Object dnValue = props.get(dnKey);
-               String dnStr = dnKey + '=' + dnValue + ',' + dnBase;
-               LdapName dn;
-               try {
-                       dn = new LdapName(dnStr);
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Cannot interpret DN " + dnStr, e);
-               }
-               if (dnValue == null)
-                       throw new IllegalArgumentException("DN key " + dnKey + " must have a value");
-               try (Writer writer = Files.newBufferedWriter(path, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
-                       writer.append("\ndn: ");
-                       writer.append(dn.toString());
-                       writer.append('\n');
-                       for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
-                               String key = keys.nextElement();
-                               Object value = props.get(key);
-                               writer.append(key);
-                               writer.append(": ");
-                               // FIXME deal with binary and multiple values
-                               writer.append(value.toString());
-                               writer.append('\n');
-                       }
-               }
-       }
-
-       static Dictionary<String, Object> loadFromProperties(Path path) throws IOException {
-               Properties toLoad = new Properties();
-               try (InputStream in = Files.newInputStream(path)) {
-                       toLoad.load(in);
-               }
-               Dictionary<String, Object> res = new Hashtable<String, Object>();
-               for (Object key : toLoad.keySet())
-                       res.put(key.toString(), toLoad.get(key));
-               return res;
-       }
-
-       /*
-        * COLLECTIONS
-        */
-       /**
-        * Convert a comma-separated separated {@link String} or a {@link String} array
-        * to a {@link List} of {@link String}, trimming them. Useful to quickly
-        * interpret OSGi services properties.
-        * 
-        * @return a {@link List} containing the trimmed {@link String}s, or an empty
-        *         {@link List} if the argument was <code>null</code>.
-        */
-       public static List<String> toStringList(Object value) {
-               List<String> values = new ArrayList<>();
-               if (value == null)
-                       return values;
-               String[] arr;
-               if (value instanceof String) {
-                       arr = ((String) value).split(",");
-               } else if (value instanceof String[]) {
-                       arr = (String[]) value;
-               } else {
-                       throw new IllegalArgumentException("Unsupported value type " + value.getClass());
-               }
-               for (String str : arr) {
-                       values.add(str.trim());
-               }
-               return values;
-       }
-
-       /** Size of an {@link Iterable}, optimised if it is a {@link Collection}. */
-       public static int size(Iterable<?> iterable) {
-               if (iterable instanceof Collection)
-                       return ((Collection<?>) iterable).size();
-
-               int size = 0;
-               for (Iterator<?> it = iterable.iterator(); it.hasNext(); size++)
-                       it.next();
-               return size;
-       }
-
-       public static <T> T getAt(Iterable<T> iterable, int index) {
-               if (iterable instanceof List) {
-                       List<T> lst = ((List<T>) iterable);
-                       if (index >= lst.size())
-                               throw new IllegalArgumentException("Index " + index + " is not available (size is " + lst.size() + ")");
-                       return lst.get(index);
-               }
-               int i = 0;
-               for (Iterator<T> it = iterable.iterator(); it.hasNext(); i++) {
-                       if (i == index)
-                               return it.next();
-                       else
-                               it.next();
-               }
-               throw new IllegalArgumentException("Index " + index + " is not available (size is " + i + ")");
-       }
-
-       /*
-        * EXCEPTIONS
-        */
-       /**
-        * Chain the messages of all causes (one per line, <b>starts with a line
-        * return</b>) without all the stack
-        */
-       public static String chainCausesMessages(Throwable t) {
-               StringBuffer buf = new StringBuffer();
-               chainCauseMessage(buf, t);
-               return buf.toString();
-       }
-
-       /** Recursive chaining of messages */
-       private static void chainCauseMessage(StringBuffer buf, Throwable t) {
-               buf.append('\n').append(' ').append(t.getClass().getCanonicalName()).append(": ").append(t.getMessage());
-               if (t.getCause() != null)
-                       chainCauseMessage(buf, t.getCause());
-       }
-
-       /*
-        * TIME
-        */
-       /** Formats time elapsed since start. */
-       public static String since(ZonedDateTime start) {
-               ZonedDateTime now = ZonedDateTime.now();
-               return duration(start, now);
-       }
-
-       /** Formats a duration. */
-       public static String duration(Temporal start, Temporal end) {
-               long count = ChronoUnit.DAYS.between(start, end);
-               if (count != 0)
-                       return count > 1 ? count + " days" : count + " day";
-               count = ChronoUnit.HOURS.between(start, end);
-               if (count != 0)
-                       return count > 1 ? count + " hours" : count + " hours";
-               count = ChronoUnit.MINUTES.between(start, end);
-               if (count != 0)
-                       return count > 1 ? count + " minutes" : count + " minute";
-               count = ChronoUnit.SECONDS.between(start, end);
-               return count > 1 ? count + " seconds" : count + " second";
-       }
-
-       /** Singleton constructor. */
-       private LangUtils() {
-
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/OS.java b/org.argeo.util/src/org/argeo/util/OS.java
deleted file mode 100644 (file)
index 174f45b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.argeo.util;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-/** When OS specific informations are needed. */
-public class OS {
-       public final static OS LOCAL = new OS();
-
-       private final String arch, name, version;
-
-       /** The OS of the running JVM */
-       protected OS() {
-               arch = System.getProperty("os.arch");
-               name = System.getProperty("os.name");
-               version = System.getProperty("os.version");
-       }
-
-       public String getArch() {
-               return arch;
-       }
-
-       public String getName() {
-               return name;
-       }
-
-       public String getVersion() {
-               return version;
-       }
-
-       public boolean isMSWindows() {
-               // only MS Windows would use such an horrendous separator...
-               return File.separatorChar == '\\';
-       }
-
-       public String[] getDefaultShellCommand() {
-               if (!isMSWindows())
-                       return new String[] { "/bin/bash", "-l", "-i" };
-               else
-                       return new String[] { "cmd.exe", "/C" };
-       }
-
-       public static long getJvmPid() {
-               return ProcessHandle.current().pid();
-//             String pidAndHost = ManagementFactory.getRuntimeMXBean().getName();
-//             return Integer.parseInt(pidAndHost.substring(0, pidAndHost.indexOf('@')));
-       }
-
-       /**
-        * Get the runtime directory. It will be the environment variable
-        * XDG_RUNTIME_DIR if it is set, or ~/.cache/argeo if not.
-        */
-       public static Path getRunDir() {
-               Path runDir;
-               String xdgRunDir = System.getenv("XDG_RUNTIME_DIR");
-               if (xdgRunDir != null) {
-                       // TODO support multiple names
-                       runDir = Paths.get(xdgRunDir);
-               } else {
-                       runDir = Paths.get(System.getProperty("user.home"), ".cache/argeo");
-               }
-               return runDir;
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/PasswordEncryption.java b/org.argeo.util/src/org/argeo/util/PasswordEncryption.java
deleted file mode 100644 (file)
index c95c787..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-package org.argeo.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.CipherOutputStream;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-
-public class PasswordEncryption {
-       public final static Integer DEFAULT_ITERATION_COUNT = 1024;
-       /** Stronger with 256, but causes problem with Oracle JVM */
-       public final static Integer DEFAULT_SECRETE_KEY_LENGTH = 256;
-       public final static Integer DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED = 128;
-       public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1";
-       public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES";
-       public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding";
-//     public final static String DEFAULT_CHARSET = "UTF-8";
-       public final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
-
-       private Integer iterationCount = DEFAULT_ITERATION_COUNT;
-       private Integer secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH;
-       private String secreteKeyFactoryName = DEFAULT_SECRETE_KEY_FACTORY;
-       private String secreteKeyEncryption = DEFAULT_SECRETE_KEY_ENCRYPTION;
-       private String cipherName = DEFAULT_CIPHER_NAME;
-
-       private static byte[] DEFAULT_SALT_8 = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
-                       (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
-       private static byte[] DEFAULT_IV_16 = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
-                       (byte) 0x35, (byte) 0xE3, (byte) 0x03, (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56,
-                       (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
-
-       private Key key;
-       private Cipher ecipher;
-       private Cipher dcipher;
-
-       private String securityProviderName = null;
-
-       /**
-        * This is up to the caller to clear the passed array. Neither copy of nor
-        * reference to the passed array is kept
-        */
-       public PasswordEncryption(char[] password) {
-               this(password, DEFAULT_SALT_8, DEFAULT_IV_16);
-       }
-
-       /**
-        * This is up to the caller to clear the passed array. Neither copies of nor
-        * references to the passed arrays are kept
-        */
-       public PasswordEncryption(char[] password, byte[] passwordSalt, byte[] initializationVector) {
-               try {
-                       initKeyAndCiphers(password, passwordSalt, initializationVector);
-               } catch (InvalidKeyException e) {
-                       Integer previousSecreteKeyLength = secreteKeyLength;
-                       secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH_RESTRICTED;
-                       System.err.println("'" + e.getMessage() + "', will use " + secreteKeyLength
-                                       + " secrete key length instead of " + previousSecreteKeyLength);
-                       try {
-                               initKeyAndCiphers(password, passwordSalt, initializationVector);
-                       } catch (GeneralSecurityException e1) {
-                               throw new IllegalStateException("Cannot get secret key (with restricted length)", e1);
-                       }
-               } catch (GeneralSecurityException e) {
-                       throw new IllegalStateException("Cannot get secret key", e);
-               }
-       }
-
-       protected void initKeyAndCiphers(char[] password, byte[] passwordSalt, byte[] initializationVector)
-                       throws GeneralSecurityException {
-               byte[] salt = new byte[8];
-               System.arraycopy(passwordSalt, 0, salt, 0, salt.length);
-               // for (int i = 0; i < password.length && i < salt.length; i++)
-               // salt[i] = (byte) password[i];
-               byte[] iv = new byte[16];
-               System.arraycopy(initializationVector, 0, iv, 0, iv.length);
-
-               SecretKeyFactory keyFac = SecretKeyFactory.getInstance(getSecretKeyFactoryName());
-               PBEKeySpec keySpec = new PBEKeySpec(password, salt, getIterationCount(), getKeyLength());
-               String secKeyEncryption = getSecretKeyEncryption();
-               if (secKeyEncryption != null) {
-                       SecretKey tmp = keyFac.generateSecret(keySpec);
-                       key = new SecretKeySpec(tmp.getEncoded(), getSecretKeyEncryption());
-               } else {
-                       key = keyFac.generateSecret(keySpec);
-               }
-               if (securityProviderName != null)
-                       ecipher = Cipher.getInstance(getCipherName(), securityProviderName);
-               else
-                       ecipher = Cipher.getInstance(getCipherName());
-               ecipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
-               dcipher = Cipher.getInstance(getCipherName());
-               dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
-       }
-
-       public void encrypt(InputStream decryptedIn, OutputStream encryptedOut) throws IOException {
-               try {
-                       CipherOutputStream out = new CipherOutputStream(encryptedOut, ecipher);
-                       StreamUtils.copy(decryptedIn, out);
-                       StreamUtils.closeQuietly(out);
-               } catch (IOException e) {
-                       throw e;
-               } finally {
-                       StreamUtils.closeQuietly(decryptedIn);
-               }
-       }
-
-       public void decrypt(InputStream encryptedIn, OutputStream decryptedOut) throws IOException {
-               try {
-                       CipherInputStream decryptedIn = new CipherInputStream(encryptedIn, dcipher);
-                       StreamUtils.copy(decryptedIn, decryptedOut);
-               } catch (IOException e) {
-                       throw e;
-               } finally {
-                       StreamUtils.closeQuietly(encryptedIn);
-               }
-       }
-
-       public byte[] encryptString(String str) {
-               ByteArrayOutputStream out = null;
-               ByteArrayInputStream in = null;
-               try {
-                       out = new ByteArrayOutputStream();
-                       in = new ByteArrayInputStream(str.getBytes(DEFAULT_CHARSET));
-                       encrypt(in, out);
-                       return out.toByteArray();
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               } finally {
-                       StreamUtils.closeQuietly(out);
-               }
-       }
-
-       /** Closes the input stream */
-       public String decryptAsString(InputStream in) {
-               ByteArrayOutputStream out = null;
-               try {
-                       out = new ByteArrayOutputStream();
-                       decrypt(in, out);
-                       return new String(out.toByteArray(), DEFAULT_CHARSET);
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               } finally {
-                       StreamUtils.closeQuietly(out);
-               }
-       }
-
-       protected Key getKey() {
-               return key;
-       }
-
-       protected Cipher getEcipher() {
-               return ecipher;
-       }
-
-       protected Cipher getDcipher() {
-               return dcipher;
-       }
-
-       protected Integer getIterationCount() {
-               return iterationCount;
-       }
-
-       protected Integer getKeyLength() {
-               return secreteKeyLength;
-       }
-
-       protected String getSecretKeyFactoryName() {
-               return secreteKeyFactoryName;
-       }
-
-       protected String getSecretKeyEncryption() {
-               return secreteKeyEncryption;
-       }
-
-       protected String getCipherName() {
-               return cipherName;
-       }
-
-       public void setIterationCount(Integer iterationCount) {
-               this.iterationCount = iterationCount;
-       }
-
-       public void setSecreteKeyLength(Integer keyLength) {
-               this.secreteKeyLength = keyLength;
-       }
-
-       public void setSecreteKeyFactoryName(String secreteKeyFactoryName) {
-               this.secreteKeyFactoryName = secreteKeyFactoryName;
-       }
-
-       public void setSecreteKeyEncryption(String secreteKeyEncryption) {
-               this.secreteKeyEncryption = secreteKeyEncryption;
-       }
-
-       public void setCipherName(String cipherName) {
-               this.cipherName = cipherName;
-       }
-
-       public void setSecurityProviderName(String securityProviderName) {
-               this.securityProviderName = securityProviderName;
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/ServiceChannel.java b/org.argeo.util/src/org/argeo/util/ServiceChannel.java
deleted file mode 100644 (file)
index 7997384..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.argeo.util;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.AsynchronousByteChannel;
-import java.nio.channels.CompletionHandler;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-
-/** An {@link AsynchronousByteChannel} based on an {@link ExecutorService}. */
-public class ServiceChannel implements AsynchronousByteChannel {
-       private final ReadableByteChannel in;
-       private final WritableByteChannel out;
-
-       private boolean open = true;
-
-       private ExecutorService executor;
-
-       public ServiceChannel(ReadableByteChannel in, WritableByteChannel out, ExecutorService executor) {
-               this.in = in;
-               this.out = out;
-               this.executor = executor;
-       }
-
-       @Override
-       public Future<Integer> read(ByteBuffer dst) {
-               return executor.submit(() -> in.read(dst));
-       }
-
-       @Override
-       public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
-               try {
-                       Future<Integer> res = read(dst);
-                       handler.completed(res.get(), attachment);
-               } catch (Exception e) {
-                       handler.failed(e, attachment);
-               }
-       }
-
-       @Override
-       public Future<Integer> write(ByteBuffer src) {
-               return executor.submit(() -> out.write(src));
-       }
-
-       @Override
-       public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
-               try {
-                       Future<Integer> res = write(src);
-                       handler.completed(res.get(), attachment);
-               } catch (Exception e) {
-                       handler.failed(e, attachment);
-               }
-       }
-
-       @Override
-       public synchronized void close() throws IOException {
-               try {
-                       in.close();
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-               try {
-                       out.close();
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-               open = false;
-               notifyAll();
-       }
-
-       @Override
-       public synchronized boolean isOpen() {
-               return open;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/StreamUtils.java b/org.argeo.util/src/org/argeo/util/StreamUtils.java
deleted file mode 100644 (file)
index 30404f1..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.argeo.util;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.util.StringJoiner;
-
-/** Stream utilities to be used when Apache Commons IO is not available. */
-public class StreamUtils {
-       private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
-
-       /*
-        * APACHE COMMONS IO (inspired)
-        */
-
-       /** @return the number of bytes */
-       public static Long copy(InputStream in, OutputStream out) throws IOException {
-               Long count = 0l;
-               byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
-               while (true) {
-                       int length = in.read(buf);
-                       if (length < 0)
-                               break;
-                       out.write(buf, 0, length);
-                       count = count + length;
-               }
-               return count;
-       }
-
-       /** @return the number of chars */
-       public static Long copy(Reader in, Writer out) throws IOException {
-               Long count = 0l;
-               char[] buf = new char[DEFAULT_BUFFER_SIZE];
-               while (true) {
-                       int length = in.read(buf);
-                       if (length < 0)
-                               break;
-                       out.write(buf, 0, length);
-                       count = count + length;
-               }
-               return count;
-       }
-
-       public static void closeQuietly(InputStream in) {
-               if (in != null)
-                       try {
-                               in.close();
-                       } catch (Exception e) {
-                               //
-                       }
-       }
-
-       public static void closeQuietly(OutputStream out) {
-               if (out != null)
-                       try {
-                               out.close();
-                       } catch (Exception e) {
-                               //
-                       }
-       }
-
-       public static void closeQuietly(Reader in) {
-               if (in != null)
-                       try {
-                               in.close();
-                       } catch (Exception e) {
-                               //
-                       }
-       }
-
-       public static void closeQuietly(Writer out) {
-               if (out != null)
-                       try {
-                               out.close();
-                       } catch (Exception e) {
-                               //
-                       }
-       }
-
-       public static String toString(BufferedReader reader) throws IOException {
-               StringJoiner sn = new StringJoiner("\n");
-               String line = null;
-               while ((line = reader.readLine()) != null)
-                       sn.add(line);
-               return sn.toString();
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/Tester.java b/org.argeo.util/src/org/argeo/util/Tester.java
deleted file mode 100644 (file)
index 31a2be4..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.argeo.util;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/** A generic tester based on Java assertions and functional programming. */
-public class Tester {
-       private Map<String, TesterStatus> results = Collections.synchronizedSortedMap(new TreeMap<>());
-
-       private ClassLoader classLoader;
-
-       /** Use {@link Thread#getContextClassLoader()} by default. */
-       public Tester() {
-               this(Thread.currentThread().getContextClassLoader());
-       }
-
-       public Tester(ClassLoader classLoader) {
-               this.classLoader = classLoader;
-       }
-
-       public void execute(String className) {
-               Class<?> clss;
-               try {
-                       clss = classLoader.loadClass(className);
-                       boolean assertionsEnabled = clss.desiredAssertionStatus();
-                       if (!assertionsEnabled)
-                               throw new IllegalStateException("Test runner " + getClass().getName()
-                                               + " requires Java assertions to be enabled. Call the JVM with the -ea argument.");
-               } catch (Exception e1) {
-                       throw new IllegalArgumentException("Cannot initalise test for " + className, e1);
-
-               }
-               List<Method> methods = findMethods(clss);
-               if (methods.size() == 0)
-                       throw new IllegalArgumentException("No test method found in " + clss);
-               // TODO make order more predictable?
-               for (Method method : methods) {
-                       String uid = method.getDeclaringClass().getName() + "#" + method.getName();
-                       TesterStatus testStatus = new TesterStatus(uid);
-                       Object obj = null;
-                       try {
-                               beforeTest(uid, method);
-                               obj = clss.getDeclaredConstructor().newInstance();
-                               method.invoke(obj);
-                               testStatus.setPassed();
-                               afterTestPassed(uid, method, obj);
-                       } catch (Exception e) {
-                               testStatus.setFailed(e);
-                               afterTestFailed(uid, method, obj, e);
-                       } finally {
-                               results.put(uid, testStatus);
-                       }
-               }
-       }
-
-       protected void beforeTest(String uid, Method method) {
-               // System.out.println(uid + ": STARTING");
-       }
-
-       protected void afterTestPassed(String uid, Method method, Object obj) {
-               System.out.println(uid + ": PASSED");
-       }
-
-       protected void afterTestFailed(String uid, Method method, Object obj, Throwable e) {
-               System.out.println(uid + ": FAILED");
-               e.printStackTrace();
-       }
-
-       protected List<Method> findMethods(Class<?> clss) {
-               List<Method> methods = new ArrayList<Method>();
-//             Method call = getMethod(clss, "call");
-//             if (call != null)
-//                     methods.add(call);
-//
-               for (Method method : clss.getMethods()) {
-                       if (method.getName().startsWith("test")) {
-                               methods.add(method);
-                       }
-               }
-               return methods;
-       }
-
-       protected Method getMethod(Class<?> clss, String name, Class<?>... parameterTypes) {
-               try {
-                       return clss.getMethod(name, parameterTypes);
-               } catch (NoSuchMethodException e) {
-                       return null;
-               } catch (SecurityException e) {
-                       throw new IllegalStateException(e);
-               }
-       }
-
-       public static void main(String[] args) {
-               // deal with arguments
-               String className;
-               if (args.length < 1) {
-                       System.err.println(usage());
-                       System.exit(1);
-                       throw new IllegalArgumentException();
-               } else {
-                       className = args[0];
-               }
-
-               Tester test = new Tester();
-               try {
-                       test.execute(className);
-               } catch (Throwable e) {
-                       e.printStackTrace();
-               }
-
-               Map<String, TesterStatus> r = test.results;
-               for (String uid : r.keySet()) {
-                       TesterStatus testStatus = r.get(uid);
-                       System.out.println(testStatus);
-               }
-       }
-
-       public static String usage() {
-               return "java " + Tester.class.getName() + " [test class name]";
-
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/TesterStatus.java b/org.argeo.util/src/org/argeo/util/TesterStatus.java
deleted file mode 100644 (file)
index d1d14ed..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.argeo.util;
-
-import java.io.Serializable;
-
-/** The status of a test. */
-public class TesterStatus implements Serializable {
-       private static final long serialVersionUID = 6272975746885487000L;
-
-       private Boolean passed = null;
-       private final String uid;
-       private Throwable throwable = null;
-
-       public TesterStatus(String uid) {
-               this.uid = uid;
-       }
-
-       /** For cloning. */
-       public TesterStatus(String uid, Boolean passed, Throwable throwable) {
-               this(uid);
-               this.passed = passed;
-               this.throwable = throwable;
-       }
-
-       public synchronized Boolean isRunning() {
-               return passed == null;
-       }
-
-       public synchronized Boolean isPassed() {
-               assert passed != null;
-               return passed;
-       }
-
-       public synchronized Boolean isFailed() {
-               assert passed != null;
-               return !passed;
-       }
-
-       public synchronized void setPassed() {
-               setStatus(true);
-       }
-
-       public synchronized void setFailed() {
-               setStatus(false);
-       }
-
-       public synchronized void setFailed(Throwable throwable) {
-               setStatus(false);
-               setThrowable(throwable);
-       }
-
-       protected void setStatus(Boolean passed) {
-               if (this.passed != null)
-                       throw new IllegalStateException("Passed status of test " + uid + " is already set (to " + passed + ")");
-               this.passed = passed;
-       }
-
-       protected void setThrowable(Throwable throwable) {
-               if (this.throwable != null)
-                       throw new IllegalStateException("Throwable of test " + uid + " is already set (to " + passed + ")");
-               this.throwable = throwable;
-       }
-
-       public String getUid() {
-               return uid;
-       }
-
-       public Throwable getThrowable() {
-               return throwable;
-       }
-
-       @Override
-       protected Object clone() throws CloneNotSupportedException {
-               // TODO Auto-generated method stub
-               return super.clone();
-       }
-
-       @Override
-       public boolean equals(Object o) {
-               if (o instanceof TesterStatus) {
-                       TesterStatus other = (TesterStatus) o;
-                       // we don't check consistency for performance purposes
-                       // this equals() is supposed to be used in collections or for transfer
-                       return other.uid.equals(uid);
-               }
-               return false;
-       }
-
-       @Override
-       public int hashCode() {
-               return uid.hashCode();
-       }
-
-       @Override
-       public String toString() {
-               return uid + "\t" + (passed ? "passed" : "failed");
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/Throughput.java b/org.argeo.util/src/org/argeo/util/Throughput.java
deleted file mode 100644 (file)
index 266ddbc..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.argeo.util;
-
-import java.text.NumberFormat;
-import java.text.ParseException;
-import java.util.Locale;
-
-/** A throughput, that is, a value per unit of time. */
-public class Throughput {
-       private final static NumberFormat usNumberFormat = NumberFormat.getInstance(Locale.US);
-
-       public enum Unit {
-               s, m, h, d
-       }
-
-       private final Double value;
-       private final Unit unit;
-
-       public Throughput(Double value, Unit unit) {
-               this.value = value;
-               this.unit = unit;
-       }
-
-       public Throughput(Long periodMs, Long count, Unit unit) {
-               if (unit.equals(Unit.s))
-                       value = ((double) count * 1000d) / periodMs;
-               else if (unit.equals(Unit.m))
-                       value = ((double) count * 60d * 1000d) / periodMs;
-               else if (unit.equals(Unit.h))
-                       value = ((double) count * 60d * 60d * 1000d) / periodMs;
-               else if (unit.equals(Unit.d))
-                       value = ((double) count * 24d * 60d * 60d * 1000d) / periodMs;
-               else
-                       throw new IllegalArgumentException("Unsupported unit " + unit);
-               this.unit = unit;
-       }
-
-       public Throughput(Double value, String unitStr) {
-               this(value, Unit.valueOf(unitStr));
-       }
-
-       public Throughput(String def) {
-               int index = def.indexOf('/');
-               if (def.length() < 3 || index <= 0 || index != def.length() - 2)
-                       throw new IllegalArgumentException(
-                                       def + " no a proper throughput definition" + " (should be <value>/<unit>, e.g. 3.54/s or 1500/h");
-               String valueStr = def.substring(0, index);
-               String unitStr = def.substring(index + 1);
-               try {
-                       this.value = usNumberFormat.parse(valueStr).doubleValue();
-               } catch (ParseException e) {
-                       throw new IllegalArgumentException("Cannot parse " + valueStr + " as a number.", e);
-               }
-               this.unit = Unit.valueOf(unitStr);
-       }
-
-       public Long asMsPeriod() {
-               if (unit.equals(Unit.s))
-                       return Math.round(1000d / value);
-               else if (unit.equals(Unit.m))
-                       return Math.round((60d * 1000d) / value);
-               else if (unit.equals(Unit.h))
-                       return Math.round((60d * 60d * 1000d) / value);
-               else if (unit.equals(Unit.d))
-                       return Math.round((24d * 60d * 60d * 1000d) / value);
-               else
-                       throw new IllegalArgumentException("Unsupported unit " + unit);
-       }
-
-       @Override
-       public String toString() {
-               return usNumberFormat.format(value) + '/' + unit;
-       }
-
-       public Double getValue() {
-               return value;
-       }
-
-       public Unit getUnit() {
-               return unit;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/Directory.java b/org.argeo.util/src/org/argeo/util/directory/Directory.java
deleted file mode 100644 (file)
index 9886589..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.argeo.util.directory;
-
-import java.util.Optional;
-
-import org.argeo.util.transaction.WorkControl;
-
-/** An information directory (typicylly LDAP). */
-public interface Directory extends HierarchyUnit {
-       String getName();
-
-       /** Whether this directory is read only. */
-       boolean isReadOnly();
-
-       /** Whether this directory is disabled. */
-       boolean isDisabled();
-
-       /** The realm (typically Kerberos) of this directory. */
-       Optional<String> getRealm();
-
-       /** Sets the transaction control used by this directory when editing. */
-       void setTransactionControl(WorkControl transactionControl);
-
-       /*
-        * HIERARCHY
-        */
-
-       /** The hierarchy unit at this path. */
-       HierarchyUnit getHierarchyUnit(String path);
-
-       /** Create a new hierarchy unit. */
-       HierarchyUnit createHierarchyUnit(String path);
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/DirectoryConf.java b/org.argeo.util/src/org/argeo/util/directory/DirectoryConf.java
deleted file mode 100644 (file)
index 4450ca4..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-package org.argeo.util.directory;
-
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
-import org.argeo.util.directory.ldap.IpaUtils;
-import org.argeo.util.naming.NamingUtils;
-
-/** Properties used to configure user admins. */
-public enum DirectoryConf {
-       /** Base DN (cannot be configured externally) */
-       baseDn(null),
-
-       /** URI of the underlying resource (cannot be configured externally) */
-       uri(null),
-
-       /** User objectClass */
-       userObjectClass("inetOrgPerson"),
-
-       /** Relative base DN for users */
-       userBase("ou=People"),
-
-       /** Groups objectClass */
-       groupObjectClass("groupOfNames"),
-
-       /** Relative base DN for users */
-       groupBase("ou=Groups"),
-
-       /** Relative base DN for users */
-       systemRoleBase("ou=Roles"),
-
-       /** Read-only source */
-       readOnly(null),
-
-       /** Disabled source */
-       disabled(null),
-
-       /** Authentication realm */
-       realm(null),
-
-       /** Override all passwords with this value (typically for testing purposes) */
-       forcedPassword(null);
-
-       public final static String FACTORY_PID = "org.argeo.osgi.useradmin.config";
-
-       public final static String SCHEME_LDAP = "ldap";
-       public final static String SCHEME_LDAPS = "ldaps";
-       public final static String SCHEME_FILE = "file";
-       public final static String SCHEME_OS = "os";
-       public final static String SCHEME_IPA = "ipa";
-
-       private final static String SECURITY_PRINCIPAL = "java.naming.security.principal";
-       private final static String SECURITY_CREDENTIALS = "java.naming.security.credentials";
-
-       /** The default value. */
-       private Object def;
-
-       DirectoryConf(Object def) {
-               this.def = def;
-       }
-
-       public Object getDefault() {
-               return def;
-       }
-
-       /**
-        * For use as Java property.
-        * 
-        * @deprecated use {@link #name()} instead
-        */
-       @Deprecated
-       public String property() {
-               return name();
-       }
-
-       public String getValue(Dictionary<String, ?> properties) {
-               Object res = getRawValue(properties);
-               if (res == null)
-                       return null;
-               return res.toString();
-       }
-
-       @SuppressWarnings("unchecked")
-       public <T> T getRawValue(Dictionary<String, ?> properties) {
-               Object res = properties.get(name());
-               if (res == null)
-                       res = getDefault();
-               return (T) res;
-       }
-
-       /** @deprecated use {@link #valueOf(String)} instead */
-       @Deprecated
-       public static DirectoryConf local(String property) {
-               return DirectoryConf.valueOf(property);
-       }
-
-       /** Hides host and credentials. */
-       public static URI propertiesAsUri(Dictionary<String, ?> properties) {
-               StringBuilder query = new StringBuilder();
-
-               boolean first = true;
-//             for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements();) {
-//                     String key = keys.nextElement();
-//                     // TODO clarify which keys are relevant (list only the enum?)
-//                     if (!key.equals("service.factoryPid") && !key.equals("cn") && !key.equals("dn")
-//                                     && !key.equals(Constants.SERVICE_PID) && !key.startsWith("java") && !key.equals(baseDn.name())
-//                                     && !key.equals(uri.name()) && !key.equals(Constants.OBJECTCLASS)
-//                                     && !key.equals(Constants.SERVICE_ID) && !key.equals("bundle.id")) {
-//                             if (first)
-//                                     first = false;
-//                             else
-//                                     query.append('&');
-//                             query.append(valueOf(key).name());
-//                             query.append('=').append(properties.get(key).toString());
-//                     }
-//             }
-
-               keys: for (DirectoryConf key : DirectoryConf.values()) {
-                       if (key.equals(baseDn) || key.equals(uri))
-                               continue keys;
-                       Object value = properties.get(key.name());
-                       if (value == null)
-                               continue keys;
-                       if (first)
-                               first = false;
-                       else
-                               query.append('&');
-                       query.append(key.name());
-                       query.append('=').append(value.toString());
-
-               }
-
-               Object bDnObj = properties.get(baseDn.name());
-               String bDn = bDnObj != null ? bDnObj.toString() : null;
-               try {
-                       return new URI(null, null, bDn != null ? '/' + bDn : null, query.length() != 0 ? query.toString() : null,
-                                       null);
-               } catch (URISyntaxException e) {
-                       throw new IllegalArgumentException("Cannot create URI from properties", e);
-               }
-       }
-
-       public static Dictionary<String, Object> uriAsProperties(String uriStr) {
-               try {
-                       Hashtable<String, Object> res = new Hashtable<String, Object>();
-                       URI u = new URI(uriStr);
-                       String scheme = u.getScheme();
-                       if (scheme != null && scheme.equals(SCHEME_IPA)) {
-                               return IpaUtils.convertIpaUri(u);
-//                             scheme = u.getScheme();
-                       }
-                       String path = u.getPath();
-                       // base DN
-                       String bDn = path.substring(path.lastIndexOf('/') + 1, path.length());
-                       if (bDn.equals("") && SCHEME_OS.equals(scheme)) {
-                               bDn = getBaseDnFromHostname();
-                       }
-
-                       if (bDn.endsWith(".ldif"))
-                               bDn = bDn.substring(0, bDn.length() - ".ldif".length());
-
-                       // Normalize base DN as LDAP name
-//                     bDn = new LdapName(bDn).toString();
-
-                       String principal = null;
-                       String credentials = null;
-                       if (scheme != null)
-                               if (scheme.equals(SCHEME_LDAP) || scheme.equals(SCHEME_LDAPS)) {
-                                       // TODO additional checks
-                                       if (u.getUserInfo() != null) {
-                                               String[] userInfo = u.getUserInfo().split(":");
-                                               principal = userInfo.length > 0 ? userInfo[0] : null;
-                                               credentials = userInfo.length > 1 ? userInfo[1] : null;
-                                       }
-                               } else if (scheme.equals(SCHEME_FILE)) {
-                               } else if (scheme.equals(SCHEME_IPA)) {
-                               } else if (scheme.equals(SCHEME_OS)) {
-                               } else
-                                       throw new IllegalArgumentException("Unsupported scheme " + scheme);
-                       Map<String, List<String>> query = NamingUtils.queryToMap(u);
-                       for (String key : query.keySet()) {
-                               DirectoryConf ldapProp = DirectoryConf.valueOf(key);
-                               List<String> values = query.get(key);
-                               if (values.size() == 1) {
-                                       res.put(ldapProp.name(), values.get(0));
-                               } else {
-                                       throw new IllegalArgumentException("Only single values are supported");
-                               }
-                       }
-                       res.put(baseDn.name(), bDn);
-                       if (SCHEME_OS.equals(scheme))
-                               res.put(readOnly.name(), "true");
-                       if (principal != null)
-                               res.put(SECURITY_PRINCIPAL, principal);
-                       if (credentials != null)
-                               res.put(SECURITY_CREDENTIALS, credentials);
-                       if (scheme != null) {// relative URIs are dealt with externally
-                               if (SCHEME_OS.equals(scheme)) {
-                                       res.put(uri.name(), SCHEME_OS + ":///");
-                               } else {
-                                       URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
-                                                       scheme.equals(SCHEME_FILE) ? u.getPath() : null, null, null);
-                                       res.put(uri.name(), bareUri.toString());
-                               }
-                       }
-                       return res;
-               } catch (URISyntaxException e) {
-                       throw new IllegalArgumentException("Cannot convert " + uri + " to properties", e);
-               }
-       }
-
-       private static String getBaseDnFromHostname() {
-               String hostname;
-               try {
-                       hostname = InetAddress.getLocalHost().getHostName();
-               } catch (UnknownHostException e) {
-                       hostname = "localhost.localdomain";
-               }
-               int dotIdx = hostname.indexOf('.');
-               if (dotIdx >= 0) {
-                       String domain = hostname.substring(dotIdx + 1, hostname.length());
-                       String bDn = ("." + domain).replaceAll("\\.", ",dc=");
-                       bDn = bDn.substring(1, bDn.length());
-                       return bDn;
-               } else {
-                       return "dc=" + hostname;
-               }
-       }
-
-       /**
-        * Hash the base DN in order to have a deterministic string to be used as a cn
-        * for the underlying user directory.
-        */
-       public static String baseDnHash(Dictionary<String, Object> properties) {
-               String bDn = (String) properties.get(baseDn.name());
-               if (bDn == null)
-                       throw new IllegalStateException("No baseDn in " + properties);
-               return DirectoryDigestUtils.sha1str(bDn);
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/DirectoryDigestUtils.java b/org.argeo.util/src/org/argeo/util/directory/DirectoryDigestUtils.java
deleted file mode 100644 (file)
index d07d2d2..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.argeo.util.directory;
-
-import java.math.BigInteger;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.util.Arrays;
-
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
-
-/** Utilities around digests, mostly those related to passwords. */
-public class DirectoryDigestUtils {
-       public final static String PASSWORD_SCHEME_SHA = "SHA";
-       public final static String PASSWORD_SCHEME_PBKDF2_SHA256 = "PBKDF2_SHA256";
-
-       public static byte[] sha1(byte[] bytes) {
-               try {
-                       MessageDigest digest = MessageDigest.getInstance("SHA1");
-                       digest.update(bytes);
-                       byte[] checksum = digest.digest();
-                       return checksum;
-               } catch (NoSuchAlgorithmException e) {
-                       throw new IllegalStateException("Cannot SHA1 digest", e);
-               }
-       }
-
-       public static byte[] toPasswordScheme(String passwordScheme, char[] password, byte[] salt, Integer iterations,
-                       Integer keyLength) {
-               try {
-                       if (PASSWORD_SCHEME_SHA.equals(passwordScheme)) {
-                               MessageDigest digest = MessageDigest.getInstance("SHA1");
-                               byte[] bytes = charsToBytes(password);
-                               digest.update(bytes);
-                               return digest.digest();
-                       } else if (PASSWORD_SCHEME_PBKDF2_SHA256.equals(passwordScheme)) {
-                               KeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength);
-
-                               SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
-                               final int ITERATION_LENGTH = 4;
-                               byte[] key = f.generateSecret(spec).getEncoded();
-                               byte[] result = new byte[ITERATION_LENGTH + salt.length + key.length];
-                               byte iterationsArr[] = new BigInteger(iterations.toString()).toByteArray();
-                               if (iterationsArr.length < ITERATION_LENGTH) {
-                                       Arrays.fill(result, 0, ITERATION_LENGTH - iterationsArr.length, (byte) 0);
-                                       System.arraycopy(iterationsArr, 0, result, ITERATION_LENGTH - iterationsArr.length,
-                                                       iterationsArr.length);
-                               } else {
-                                       System.arraycopy(iterationsArr, 0, result, 0, ITERATION_LENGTH);
-                               }
-                               System.arraycopy(salt, 0, result, ITERATION_LENGTH, salt.length);
-                               System.arraycopy(key, 0, result, ITERATION_LENGTH + salt.length, key.length);
-                               return result;
-                       } else {
-                               throw new UnsupportedOperationException("Unkown password scheme " + passwordScheme);
-                       }
-               } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
-                       throw new IllegalStateException("Cannot digest", e);
-               }
-       }
-
-       public static char[] bytesToChars(Object obj) {
-               if (obj instanceof char[])
-                       return (char[]) obj;
-               if (!(obj instanceof byte[]))
-                       throw new IllegalArgumentException(obj.getClass() + " is not a byte array");
-               ByteBuffer fromBuffer = ByteBuffer.wrap((byte[]) obj);
-               CharBuffer toBuffer = StandardCharsets.UTF_8.decode(fromBuffer);
-               char[] res = Arrays.copyOfRange(toBuffer.array(), toBuffer.position(), toBuffer.limit());
-               // Arrays.fill(fromBuffer.array(), (byte) 0); // clear sensitive data
-               // Arrays.fill((byte[]) obj, (byte) 0); // clear sensitive data
-               // Arrays.fill(toBuffer.array(), '\u0000'); // clear sensitive data
-               return res;
-       }
-
-       public static byte[] charsToBytes(char[] chars) {
-               CharBuffer charBuffer = CharBuffer.wrap(chars);
-               ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(charBuffer);
-               byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
-               // Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
-               // Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
-               return bytes;
-       }
-
-       public static String sha1str(String str) {
-               byte[] hash = sha1(str.getBytes(StandardCharsets.UTF_8));
-               return encodeHexString(hash);
-       }
-
-       final private static char[] hexArray = "0123456789abcdef".toCharArray();
-
-       /**
-        * From
-        * http://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to
-        * -a-hex-string-in-java
-        */
-       public static String encodeHexString(byte[] bytes) {
-               char[] hexChars = new char[bytes.length * 2];
-               for (int j = 0; j < bytes.length; j++) {
-                       int v = bytes[j] & 0xFF;
-                       hexChars[j * 2] = hexArray[v >>> 4];
-                       hexChars[j * 2 + 1] = hexArray[v & 0x0F];
-               }
-               return new String(hexChars);
-       }
-
-       /** singleton */
-       private DirectoryDigestUtils() {
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/HierarchyUnit.java b/org.argeo.util/src/org/argeo/util/directory/HierarchyUnit.java
deleted file mode 100644 (file)
index 947b6bc..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.argeo.util.directory;
-
-import java.util.Dictionary;
-import java.util.Locale;
-
-/** A unit within the high-level organisational structure of a directory. */
-public interface HierarchyUnit {
-       /** Name to use in paths. */
-       String getHierarchyUnitName();
-
-       /** Name to use in UI. */
-       String getHierarchyUnitLabel(Locale locale);
-
-       /**
-        * The parent {@link HierarchyUnit}, or <code>null</code> if a
-        * {@link Directory}.
-        */
-       HierarchyUnit getParent();
-
-       /** Direct children {@link HierarchyUnit}s. */
-       Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly);
-
-       /**
-        * Whether this is an arbitrary named and placed {@link HierarchyUnit}.
-        * 
-        * @return <code>true</code> if functional, <code>false</code> is technical
-        *         (e.g. People, Groups, etc.)
-        */
-       boolean isFunctional();
-
-       /**
-        * The base of this organisational unit within the hierarchy. This would
-        * typically be an LDAP base DN.
-        */
-       String getBase();
-
-       /** The related {@link Directory}. */
-       Directory getDirectory();
-
-       /** Its metadata (typically LDAP attributes). */
-       Dictionary<String, Object> getProperties();
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java b/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java
deleted file mode 100644 (file)
index 28d8d08..0000000
+++ /dev/null
@@ -1,560 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import static org.argeo.util.directory.ldap.LdapNameUtils.toLdapName;
-
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Locale;
-import java.util.Optional;
-import java.util.StringJoiner;
-
-import javax.naming.InvalidNameException;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-import javax.transaction.xa.XAResource;
-
-import org.argeo.osgi.useradmin.OsUserDirectory;
-import org.argeo.util.directory.Directory;
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-import org.argeo.util.transaction.WorkControl;
-import org.argeo.util.transaction.WorkingCopyXaResource;
-import org.argeo.util.transaction.XAResourceProvider;
-
-/** A {@link Directory} based either on LDAP or LDIF. */
-public abstract class AbstractLdapDirectory implements Directory, XAResourceProvider {
-       protected static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
-       protected static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
-
-       private final LdapName baseDn;
-       private final Hashtable<String, Object> configProperties;
-       private final Rdn userBaseRdn, groupBaseRdn, systemRoleBaseRdn;
-       private final String userObjectClass, groupObjectClass;
-       private String memberAttributeId = "member";
-
-       private final boolean readOnly;
-       private final boolean disabled;
-       private final String uri;
-
-       private String forcedPassword;
-
-       private final boolean scoped;
-
-       private List<String> credentialAttributeIds = Arrays
-                       .asList(new String[] { LdapAttrs.userPassword.name(), LdapAttrs.authPassword.name() });
-
-       private WorkControl transactionControl;
-       private WorkingCopyXaResource<LdapEntryWorkingCopy> xaResource;
-
-       private LdapDirectoryDao directoryDao;
-
-       public AbstractLdapDirectory(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
-               this.configProperties = new Hashtable<String, Object>();
-               for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
-                       String key = keys.nextElement();
-                       configProperties.put(key, props.get(key));
-               }
-
-               String baseDnStr = DirectoryConf.baseDn.getValue(configProperties);
-               if (baseDnStr == null)
-                       throw new IllegalArgumentException("Base DN must be specified: " + configProperties);
-               baseDn = toLdapName(baseDnStr);
-               this.scoped = scoped;
-
-               if (uriArg != null) {
-                       uri = uriArg.toString();
-                       // uri from properties is ignored
-               } else {
-                       String uriStr = DirectoryConf.uri.getValue(configProperties);
-                       if (uriStr == null)
-                               uri = null;
-                       else
-                               uri = uriStr;
-               }
-
-               forcedPassword = DirectoryConf.forcedPassword.getValue(configProperties);
-
-               userObjectClass = DirectoryConf.userObjectClass.getValue(configProperties);
-               groupObjectClass = DirectoryConf.groupObjectClass.getValue(configProperties);
-
-               String userBase = DirectoryConf.userBase.getValue(configProperties);
-               String groupBase = DirectoryConf.groupBase.getValue(configProperties);
-               String systemRoleBase = DirectoryConf.systemRoleBase.getValue(configProperties);
-               try {
-//                     baseDn = new LdapName(UserAdminConf.baseDn.getValue(properties));
-                       userBaseRdn = new Rdn(userBase);
-//                     userBaseDn = new LdapName(userBase + "," + baseDn);
-                       groupBaseRdn = new Rdn(groupBase);
-//                     groupBaseDn = new LdapName(groupBase + "," + baseDn);
-                       systemRoleBaseRdn = new Rdn(systemRoleBase);
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException(
-                                       "Badly formated base DN " + DirectoryConf.baseDn.getValue(configProperties), e);
-               }
-
-               // read only
-               String readOnlyStr = DirectoryConf.readOnly.getValue(configProperties);
-               if (readOnlyStr == null) {
-                       readOnly = readOnlyDefault(uri);
-                       configProperties.put(DirectoryConf.readOnly.name(), Boolean.toString(readOnly));
-               } else
-                       readOnly = Boolean.parseBoolean(readOnlyStr);
-
-               // disabled
-               String disabledStr = DirectoryConf.disabled.getValue(configProperties);
-               if (disabledStr != null)
-                       disabled = Boolean.parseBoolean(disabledStr);
-               else
-                       disabled = false;
-               if (!getRealm().isEmpty()) {
-                       // IPA multiple LDAP causes URI parsing to fail
-                       // TODO manage generic redundant LDAP case
-                       directoryDao = new LdapDao(this);
-               } else {
-                       if (uri != null) {
-                               URI u = URI.create(uri);
-                               if (DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
-                                               || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
-                                       directoryDao = new LdapDao(this);
-                               } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
-                                       directoryDao = new LdifDao(this);
-                               } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
-                                       directoryDao = new OsUserDirectory(this);
-                                       // singleUser = true;
-                               } else {
-                                       throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
-                               }
-                       } else {
-                               // in memory
-                               directoryDao = new LdifDao(this);
-                       }
-               }
-               if (directoryDao != null)
-                       xaResource = new WorkingCopyXaResource<>(directoryDao);
-       }
-
-       /*
-        * INITIALISATION
-        */
-
-       public void init() {
-               getDirectoryDao().init();
-       }
-
-       public void destroy() {
-               getDirectoryDao().destroy();
-       }
-
-       /*
-        * CREATION
-        */
-       protected abstract LdapEntry newUser(LdapName name);
-
-       protected abstract LdapEntry newGroup(LdapName name);
-
-       /*
-        * EDITION
-        */
-
-       public boolean isEditing() {
-               return xaResource.wc() != null;
-       }
-
-       public LdapEntryWorkingCopy getWorkingCopy() {
-               LdapEntryWorkingCopy wc = xaResource.wc();
-               if (wc == null)
-                       return null;
-               return wc;
-       }
-
-       public void checkEdit() {
-               if (xaResource.wc() == null) {
-                       try {
-                               transactionControl.getWorkContext().registerXAResource(xaResource, null);
-                       } catch (Exception e) {
-                               throw new IllegalStateException("Cannot enlist " + xaResource, e);
-                       }
-               } else {
-               }
-       }
-
-       public void setTransactionControl(WorkControl transactionControl) {
-               this.transactionControl = transactionControl;
-       }
-
-       public XAResource getXaResource() {
-               return xaResource;
-       }
-
-       public boolean removeEntry(LdapName dn) {
-               checkEdit();
-               LdapEntryWorkingCopy wc = getWorkingCopy();
-               boolean actuallyDeleted;
-               if (getDirectoryDao().entryExists(dn) || wc.getNewData().containsKey(dn)) {
-                       LdapEntry user = doGetRole(dn);
-                       wc.getDeletedData().put(dn, user);
-                       actuallyDeleted = true;
-               } else {// just removing from groups (e.g. system roles)
-                       actuallyDeleted = false;
-               }
-               for (LdapName groupDn : getDirectoryDao().getDirectGroups(dn)) {
-                       LdapEntry group = doGetRole(groupDn);
-                       group.getAttributes().get(getMemberAttributeId()).remove(dn.toString());
-               }
-               return actuallyDeleted;
-       }
-
-       /*
-        * RETRIEVAL
-        */
-
-       protected LdapEntry doGetRole(LdapName dn) {
-               LdapEntryWorkingCopy wc = getWorkingCopy();
-               LdapEntry user;
-               try {
-                       user = getDirectoryDao().doGetEntry(dn);
-               } catch (NameNotFoundException e) {
-                       user = null;
-               }
-               if (wc != null) {
-                       if (user == null && wc.getNewData().containsKey(dn))
-                               user = wc.getNewData().get(dn);
-                       else if (wc.getDeletedData().containsKey(dn))
-                               user = null;
-               }
-               return user;
-       }
-
-       protected void collectGroups(LdapEntry user, List<LdapEntry> allRoles) {
-               Attributes attrs = user.getAttributes();
-               // TODO centralize attribute name
-               Attribute memberOf = attrs.get(LdapAttrs.memberOf.name());
-               // if user belongs to this directory, we only check memberOf
-               if (memberOf != null && user.getDn().startsWith(getBaseDn())) {
-                       try {
-                               NamingEnumeration<?> values = memberOf.getAll();
-                               while (values.hasMore()) {
-                                       Object value = values.next();
-                                       LdapName groupDn = new LdapName(value.toString());
-                                       LdapEntry group = doGetRole(groupDn);
-                                       if (group != null) {
-                                               allRoles.add(group);
-                                       } else {
-                                               // user doesn't have the right to retrieve role, but we know it exists
-                                               // otherwise memberOf would not work
-                                               group = newGroup(groupDn);
-                                               allRoles.add(group);
-                                       }
-                               }
-                       } catch (NamingException e) {
-                               throw new IllegalStateException("Cannot get memberOf groups for " + user, e);
-                       }
-               } else {
-                       directGroups: for (LdapName groupDn : getDirectoryDao().getDirectGroups(user.getDn())) {
-                               LdapEntry group = doGetRole(groupDn);
-                               if (group != null) {
-                                       if (allRoles.contains(group)) {
-                                               // important in order to avoi loops
-                                               continue directGroups;
-                                       }
-                                       allRoles.add(group);
-                                       collectGroups(group, allRoles);
-                               }
-                       }
-               }
-       }
-
-       /*
-        * HIERARCHY
-        */
-       @Override
-       public HierarchyUnit getHierarchyUnit(String path) {
-               LdapName dn = pathToName(path);
-               return directoryDao.doGetHierarchyUnit(dn);
-       }
-
-       @Override
-       public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
-               return directoryDao.doGetDirectHierarchyUnits(baseDn, functionalOnly);
-       }
-
-       @Override
-       public String getHierarchyUnitName() {
-               return getName();
-       }
-
-       @Override
-       public String getHierarchyUnitLabel(Locale locale) {
-               String key = LdapNameUtils.getLastRdn(getBaseDn()).getType();
-               Object value = LdapEntry.getLocalized(asLdapEntry().getProperties(), key, locale);
-               if (value == null)
-                       value = getHierarchyUnitName();
-               assert value != null;
-               return value.toString();
-       }
-
-       @Override
-       public HierarchyUnit getParent() {
-               return null;
-       }
-
-       @Override
-       public boolean isFunctional() {
-               return true;
-       }
-
-       @Override
-       public Directory getDirectory() {
-               return this;
-       }
-
-       @Override
-       public HierarchyUnit createHierarchyUnit(String path) {
-               checkEdit();
-               LdapEntryWorkingCopy wc = getWorkingCopy();
-               LdapName dn = pathToName(path);
-               if ((getDirectoryDao().entryExists(dn) && !wc.getDeletedData().containsKey(dn))
-                               || wc.getNewData().containsKey(dn))
-                       throw new IllegalArgumentException("Already a hierarchy unit " + path);
-               BasicAttributes attrs = new BasicAttributes(true);
-               attrs.put(LdapAttrs.objectClass.name(), LdapObjs.organizationalUnit.name());
-               Rdn nameRdn = dn.getRdn(dn.size() - 1);
-               // TODO deal with multiple attr RDN
-               attrs.put(nameRdn.getType(), nameRdn.getValue());
-               wc.getModifiedData().put(dn, attrs);
-               LdapHierarchyUnit newHierarchyUnit = new LdapHierarchyUnit(this, dn);
-               wc.getNewData().put(dn, newHierarchyUnit);
-               return newHierarchyUnit;
-       }
-
-       /*
-        * PATHS
-        */
-
-       @Override
-       public String getBase() {
-               return getBaseDn().toString();
-       }
-
-       @Override
-       public String getName() {
-               return nameToSimple(getBaseDn(), ".");
-       }
-
-       protected String nameToRelativePath(LdapName dn) {
-               LdapName name = LdapNameUtils.relativeName(getBaseDn(), dn);
-               return nameToSimple(name, "/");
-       }
-
-       protected String nameToSimple(LdapName name, String separator) {
-               StringJoiner path = new StringJoiner(separator);
-               for (int i = 0; i < name.size(); i++) {
-                       path.add(name.getRdn(i).getValue().toString());
-               }
-               return path.toString();
-
-       }
-
-       protected LdapName pathToName(String path) {
-               try {
-                       LdapName name = (LdapName) getBaseDn().clone();
-                       String[] segments = path.split("/");
-                       Rdn parentRdn = null;
-                       // segments[0] is the directory itself
-                       for (int i = 0; i < segments.length; i++) {
-                               String segment = segments[i];
-                               // TODO make attr names configurable ?
-                               String attr = path.startsWith("accounts/")/* IPA */ ? LdapAttrs.cn.name() : LdapAttrs.ou.name();
-                               if (parentRdn != null) {
-                                       if (getUserBaseRdn().equals(parentRdn))
-                                               attr = LdapAttrs.uid.name();
-                                       else if (getGroupBaseRdn().equals(parentRdn))
-                                               attr = LdapAttrs.cn.name();
-                                       else if (getSystemRoleBaseRdn().equals(parentRdn))
-                                               attr = LdapAttrs.cn.name();
-                               }
-                               Rdn rdn = new Rdn(attr, segment);
-                               name.add(rdn);
-                               parentRdn = rdn;
-                       }
-                       return name;
-               } catch (InvalidNameException e) {
-                       throw new IllegalStateException("Cannot get role " + path, e);
-               }
-
-       }
-
-       /*
-        * UTILITIES
-        */
-       protected boolean isExternal(LdapName name) {
-               return !name.startsWith(baseDn);
-       }
-
-       protected static boolean hasObjectClass(Attributes attrs, LdapObjs objectClass) {
-               return hasObjectClass(attrs, objectClass.name());
-       }
-
-       protected static boolean hasObjectClass(Attributes attrs, String objectClass) {
-               try {
-                       Attribute attr = attrs.get(LdapAttrs.objectClass.name());
-                       NamingEnumeration<?> en = attr.getAll();
-                       while (en.hasMore()) {
-                               String v = en.next().toString();
-                               if (v.equalsIgnoreCase(objectClass))
-                                       return true;
-
-                       }
-                       return false;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot search for objectClass " + objectClass, e);
-               }
-       }
-
-       private static boolean readOnlyDefault(String uriStr) {
-               if (uriStr == null)
-                       return true;
-               /// TODO make it more generic
-               URI uri;
-               try {
-                       uri = new URI(uriStr.split(" ")[0]);
-               } catch (URISyntaxException e) {
-                       throw new IllegalArgumentException(e);
-               }
-               if (uri.getScheme() == null)
-                       return false;// assume relative file to be writable
-               if (uri.getScheme().equals(DirectoryConf.SCHEME_FILE)) {
-                       File file = new File(uri);
-                       if (file.exists())
-                               return !file.canWrite();
-                       else
-                               return !file.getParentFile().canWrite();
-               } else if (uri.getScheme().equals(DirectoryConf.SCHEME_LDAP)) {
-                       if (uri.getAuthority() != null)// assume writable if authenticated
-                               return false;
-               } else if (uri.getScheme().equals(DirectoryConf.SCHEME_OS)) {
-                       return true;
-               }
-               return true;// read only by default
-       }
-
-       /*
-        * AS AN ENTRY
-        */
-       public LdapEntry asLdapEntry() {
-               try {
-                       return directoryDao.doGetEntry(baseDn);
-               } catch (NameNotFoundException e) {
-                       throw new IllegalStateException("Cannot get " + baseDn + " entry", e);
-               }
-       }
-
-       public Dictionary<String, Object> getProperties() {
-               return asLdapEntry().getProperties();
-       }
-
-       /*
-        * ACCESSORS
-        */
-       @Override
-       public Optional<String> getRealm() {
-               Object realm = configProperties.get(DirectoryConf.realm.name());
-               if (realm == null)
-                       return Optional.empty();
-               return Optional.of(realm.toString());
-       }
-
-       public LdapName getBaseDn() {
-               return (LdapName) baseDn.clone();
-       }
-
-       public boolean isReadOnly() {
-               return readOnly;
-       }
-
-       public boolean isDisabled() {
-               return disabled;
-       }
-
-       public Rdn getUserBaseRdn() {
-               return userBaseRdn;
-       }
-
-       public Rdn getGroupBaseRdn() {
-               return groupBaseRdn;
-       }
-
-       public Rdn getSystemRoleBaseRdn() {
-               return systemRoleBaseRdn;
-       }
-
-//     public Dictionary<String, Object> getConfigProperties() {
-//             return configProperties;
-//     }
-
-       public Dictionary<String, Object> cloneConfigProperties() {
-               return new Hashtable<>(configProperties);
-       }
-
-       public String getForcedPassword() {
-               return forcedPassword;
-       }
-
-       public boolean isScoped() {
-               return scoped;
-       }
-
-       public List<String> getCredentialAttributeIds() {
-               return credentialAttributeIds;
-       }
-
-       public String getUri() {
-               return uri;
-       }
-
-       public LdapDirectoryDao getDirectoryDao() {
-               return directoryDao;
-       }
-
-       /** dn can be null, in that case a default should be returned. */
-       public String getUserObjectClass() {
-               return userObjectClass;
-       }
-
-       public String getGroupObjectClass() {
-               return groupObjectClass;
-       }
-
-       public String getMemberAttributeId() {
-               return memberAttributeId;
-       }
-
-       /*
-        * OBJECT METHODS
-        */
-
-       @Override
-       public int hashCode() {
-               return baseDn.hashCode();
-       }
-
-       @Override
-       public String toString() {
-               return "Directory " + baseDn.toString();
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectoryDao.java b/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectoryDao.java
deleted file mode 100644 (file)
index 8e13288..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-
-public abstract class AbstractLdapDirectoryDao implements LdapDirectoryDao {
-
-       private AbstractLdapDirectory directory;
-
-       public AbstractLdapDirectoryDao(AbstractLdapDirectory directory) {
-               this.directory = directory;
-
-       }
-
-       public AbstractLdapDirectory getDirectory() {
-               return directory;
-       }
-
-       @Override
-       public LdapEntryWorkingCopy newWorkingCopy() {
-               return new LdapEntryWorkingCopy();
-       }
-
-       @Override
-       public LdapEntry newUser(LdapName name) {
-               return getDirectory().newUser(name);
-       }
-
-       @Override
-       public LdapEntry newGroup(LdapName name) {
-               return getDirectory().newGroup(name);
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/AttributesDictionary.java b/org.argeo.util/src/org/argeo/util/directory/ldap/AttributesDictionary.java
deleted file mode 100644 (file)
index 7b0095f..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.util.Dictionary;
-import java.util.Enumeration;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-
-public class AttributesDictionary extends Dictionary<String, Object> {
-       private final Attributes attributes;
-
-       /** The provided attributes is wrapped, not copied. */
-       public AttributesDictionary(Attributes attributes) {
-               if (attributes == null)
-                       throw new IllegalArgumentException("Attributes cannot be null");
-               this.attributes = attributes;
-       }
-
-       @Override
-       public int size() {
-               return attributes.size();
-       }
-
-       @Override
-       public boolean isEmpty() {
-               return attributes.size() == 0;
-       }
-
-       @Override
-       public Enumeration<String> keys() {
-               NamingEnumeration<String> namingEnumeration = attributes.getIDs();
-               return new Enumeration<String>() {
-
-                       @Override
-                       public boolean hasMoreElements() {
-                               return namingEnumeration.hasMoreElements();
-                       }
-
-                       @Override
-                       public String nextElement() {
-                               return namingEnumeration.nextElement();
-                       }
-
-               };
-       }
-
-       @Override
-       public Enumeration<Object> elements() {
-               NamingEnumeration<String> namingEnumeration = attributes.getIDs();
-               return new Enumeration<Object>() {
-
-                       @Override
-                       public boolean hasMoreElements() {
-                               return namingEnumeration.hasMoreElements();
-                       }
-
-                       @Override
-                       public Object nextElement() {
-                               String key = namingEnumeration.nextElement();
-                               return get(key);
-                       }
-
-               };
-       }
-
-       @Override
-       /** @returns a <code>String</code> or <code>String[]</code> */
-       public Object get(Object key) {
-               try {
-                       if (key == null)
-                               throw new IllegalArgumentException("Key cannot be null");
-                       Attribute attr = attributes.get(key.toString());
-                       if (attr == null)
-                               return null;
-                       if (attr.size() == 0)
-                               throw new IllegalStateException("There must be at least one value");
-                       else if (attr.size() == 1) {
-                               return attr.get().toString();
-                       } else {// multiple
-                               String[] res = new String[attr.size()];
-                               for (int i = 0; i < attr.size(); i++) {
-                                       Object value = attr.get();
-                                       if (value == null)
-                                               throw new RuntimeException("Values cannot be null");
-                                       res[i] = attr.get(i).toString();
-                               }
-                               return res;
-                       }
-               } catch (NamingException e) {
-                       throw new RuntimeException("Cannot get value for " + key, e);
-               }
-       }
-
-       @Override
-       public Object put(String key, Object value) {
-               if (key == null)
-                       throw new IllegalArgumentException("Key cannot be null");
-               if (value == null)
-                       throw new IllegalArgumentException("Value cannot be null");
-
-               Object oldValue = get(key);
-               Attribute attr = attributes.get(key);
-               if (attr == null) {
-                       attr = new BasicAttribute(key);
-                       attributes.put(attr);
-               }
-
-               if (value instanceof String[]) {
-                       String[] values = (String[]) value;
-                       // clean additional values
-                       for (int i = values.length; i < attr.size(); i++)
-                               attr.remove(i);
-                       // set values
-                       for (int i = 0; i < values.length; i++) {
-                               attr.set(i, values[i]);
-                       }
-               } else {
-                       if (attr.size() > 1)
-                               throw new IllegalArgumentException("Attribute " + key + " is multi-valued");
-                       if (attr.size() == 1) {
-                               try {
-                                       if (!attr.get(0).equals(value))
-                                               attr.set(0, value.toString());
-                               } catch (NamingException e) {
-                                       throw new RuntimeException("Cannot check existing value", e);
-                               }
-                       } else {
-                               attr.add(value.toString());
-                       }
-               }
-               return oldValue;
-       }
-
-       @Override
-       public Object remove(Object key) {
-               if (key == null)
-                       throw new IllegalArgumentException("Key cannot be null");
-               Object oldValue = get(key);
-               if (oldValue == null)
-                       return null;
-               return attributes.remove(key.toString());
-       }
-
-       /**
-        * Copy the <b>content</b> of an {@link Attributes} to the provided
-        * {@link Dictionary}.
-        */
-       public static void copy(Attributes attributes, Dictionary<String, Object> dictionary) {
-               AttributesDictionary ad = new AttributesDictionary(attributes);
-               Enumeration<String> keys = ad.keys();
-               while (keys.hasMoreElements()) {
-                       String key = keys.nextElement();
-                       dictionary.put(key, ad.get(key));
-               }
-       }
-
-       /**
-        * Copy a {@link Dictionary} into an {@link Attributes}.
-        */
-       public static void copy(Dictionary<String, Object> dictionary, Attributes attributes) {
-               AttributesDictionary ad = new AttributesDictionary(attributes);
-               Enumeration<String> keys = dictionary.keys();
-               while (keys.hasMoreElements()) {
-                       String key = keys.nextElement();
-                       ad.put(key, dictionary.get(key));
-               }
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/AuthPassword.java b/org.argeo.util/src/org/argeo/util/directory/ldap/AuthPassword.java
deleted file mode 100644 (file)
index e10f457..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.StringTokenizer;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-import org.argeo.util.naming.LdapAttrs;
-
-/** LDAP authPassword field according to RFC 3112 */
-public class AuthPassword implements CallbackHandler {
-       private final String authScheme;
-       private final String authInfo;
-       private final String authValue;
-
-       public AuthPassword(String value) {
-               StringTokenizer st = new StringTokenizer(value, "$");
-               // TODO make it more robust, deal with bad formatting
-               this.authScheme = st.nextToken().trim();
-               this.authInfo = st.nextToken().trim();
-               this.authValue = st.nextToken().trim();
-
-               String expectedAuthScheme = getExpectedAuthScheme();
-               if (expectedAuthScheme != null && !authScheme.equals(expectedAuthScheme))
-                       throw new IllegalArgumentException(
-                                       "Auth scheme " + authScheme + " is not compatible with " + expectedAuthScheme);
-       }
-
-       protected AuthPassword(String authInfo, String authValue) {
-               this.authScheme = getExpectedAuthScheme();
-               if (authScheme == null)
-                       throw new IllegalArgumentException("Expected auth scheme cannot be null");
-               this.authInfo = authInfo;
-               this.authValue = authValue;
-       }
-
-       protected AuthPassword(AuthPassword authPassword) {
-               this.authScheme = authPassword.getAuthScheme();
-               this.authInfo = authPassword.getAuthInfo();
-               this.authValue = authPassword.getAuthValue();
-       }
-
-       protected String getExpectedAuthScheme() {
-               return null;
-       }
-
-       protected boolean matchAuthValue(Object object) {
-               return authValue.equals(object.toString());
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (!(obj instanceof AuthPassword))
-                       return false;
-               AuthPassword authPassword = (AuthPassword) obj;
-               return authScheme.equals(authPassword.authScheme) && authInfo.equals(authPassword.authInfo)
-                               && authValue.equals(authValue);
-       }
-
-       public boolean keyEquals(AuthPassword authPassword) {
-               return authScheme.equals(authPassword.authScheme) && authInfo.equals(authPassword.authInfo);
-       }
-
-       @Override
-       public int hashCode() {
-               return authValue.hashCode();
-       }
-
-       @Override
-       public String toString() {
-               return toAuthPassword();
-       }
-
-       public final String toAuthPassword() {
-               return getAuthScheme() + '$' + authInfo + '$' + authValue;
-       }
-
-       public String getAuthScheme() {
-               return authScheme;
-       }
-
-       public String getAuthInfo() {
-               return authInfo;
-       }
-
-       public String getAuthValue() {
-               return authValue;
-       }
-
-       public static AuthPassword matchAuthValue(Attributes attributes, char[] value) {
-               try {
-                       Attribute authPassword = attributes.get(LdapAttrs.authPassword.name());
-                       if (authPassword != null) {
-                               NamingEnumeration<?> values = authPassword.getAll();
-                               while (values.hasMore()) {
-                                       Object val = values.next();
-                                       AuthPassword token = new AuthPassword(val.toString());
-                                       String auth;
-                                       if (Arrays.binarySearch(value, '$') >= 0) {
-                                               auth = token.authInfo + '$' + token.authValue;
-                                       } else {
-                                               auth = token.authValue;
-                                       }
-                                       if (Arrays.equals(auth.toCharArray(), value))
-                                               return token;
-                                       // if (token.matchAuthValue(value))
-                                       // return token;
-                               }
-                       }
-                       return null;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot check attribute", e);
-               }
-       }
-
-       public static boolean remove(Attributes attributes, AuthPassword value) {
-               Attribute authPassword = attributes.get(LdapAttrs.authPassword.name());
-               return authPassword.remove(value.toAuthPassword());
-       }
-
-       @Override
-       public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-               for (Callback callback : callbacks) {
-                       if (callback instanceof NameCallback)
-                               ((NameCallback) callback).setName(toAuthPassword());
-                       else if (callback instanceof PasswordCallback)
-                               ((PasswordCallback) callback).setPassword(getAuthValue().toCharArray());
-               }
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/DefaultLdapEntry.java b/org.argeo.util/src/org/argeo/util/directory/ldap/DefaultLdapEntry.java
deleted file mode 100644 (file)
index 6b6154d..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import static java.nio.charset.StandardCharsets.US_ASCII;
-
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Objects;
-import java.util.StringJoiner;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.DirectoryDigestUtils;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-
-/** An entry in an LDAP (or LDIF) directory. */
-public class DefaultLdapEntry implements LdapEntry {
-       private final AbstractLdapDirectory directory;
-
-       private final LdapName dn;
-
-//     private Attributes publishedAttributes;
-
-       // Temporarily expose the fields
-       private AttributeDictionary properties;
-       private AttributeDictionary credentials;
-
-       protected DefaultLdapEntry(AbstractLdapDirectory directory, LdapName dn) {
-               Objects.requireNonNull(directory);
-               Objects.requireNonNull(dn);
-               this.directory = directory;
-               this.dn = dn;
-//             this.publishedAttributes = attributes;
-//             properties = new AttributeDictionary(false);
-//             credentials = new AttributeDictionary(true);
-       }
-
-       @Override
-       public LdapName getDn() {
-               return dn;
-       }
-
-       public synchronized Attributes getAttributes() {
-//             // lazy loading
-//             if (publishedAttributes == null)
-//                     publishedAttributes = getDirectory().getDirectoryDao().doGetAttributes(dn);
-               return isEditing() ? getModifiedAttributes() : getDirectory().getDirectoryDao().doGetAttributes(dn);
-       }
-
-       @Override
-       public List<LdapName> getReferences(String attributeId) {
-               Attribute memberAttribute = getAttributes().get(attributeId);
-               if (memberAttribute == null)
-                       return new ArrayList<LdapName>();
-               try {
-                       List<LdapName> roles = new ArrayList<LdapName>();
-                       NamingEnumeration<?> values = memberAttribute.getAll();
-                       while (values.hasMore()) {
-                               LdapName dn = new LdapName(values.next().toString());
-                               roles.add(dn);
-                       }
-                       return roles;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get members", e);
-               }
-
-       }
-
-       /** Should only be called from working copy thread. */
-       protected synchronized Attributes getModifiedAttributes() {
-               assert getWc() != null;
-               return getWc().getModifiedData().get(getDn());
-       }
-
-       protected synchronized boolean isEditing() {
-               return getWc() != null && getModifiedAttributes() != null;
-       }
-
-       private synchronized LdapEntryWorkingCopy getWc() {
-               return directory.getWorkingCopy();
-       }
-
-       protected synchronized void startEditing() {
-//             if (frozen)
-//                     throw new IllegalStateException("Cannot edit frozen view");
-               if (directory.isReadOnly())
-                       throw new IllegalStateException("User directory is read-only");
-               assert getModifiedAttributes() == null;
-               getWc().startEditing(this);
-               // modifiedAttributes = (Attributes) publishedAttributes.clone();
-       }
-
-       public synchronized void publishAttributes(Attributes modifiedAttributes) {
-//             publishedAttributes = modifiedAttributes;
-       }
-
-       /*
-        * PROPERTIES
-        */
-       @Override
-       public Dictionary<String, Object> getProperties() {
-               if (properties == null)
-                       properties = new AttributeDictionary(false);
-               return properties;
-       }
-
-       public Dictionary<String, Object> getCredentials() {
-               if (credentials == null)
-                       credentials = new AttributeDictionary(true);
-               return credentials;
-       }
-
-       /*
-        * CREDENTIALS
-        */
-       @Override
-       public boolean hasCredential(String key, Object value) {
-               if (key == null) {
-                       // TODO check other sources (like PKCS12)
-                       // String pwd = new String((char[]) value);
-                       // authPassword (RFC 312 https://tools.ietf.org/html/rfc3112)
-                       char[] password = DirectoryDigestUtils.bytesToChars(value);
-
-                       if (getDirectory().getForcedPassword() != null
-                                       && getDirectory().getForcedPassword().equals(new String(password)))
-                               return true;
-
-                       AuthPassword authPassword = AuthPassword.matchAuthValue(getAttributes(), password);
-                       if (authPassword != null) {
-                               if (authPassword.getAuthScheme().equals(SharedSecret.X_SHARED_SECRET)) {
-                                       SharedSecret onceToken = new SharedSecret(authPassword);
-                                       if (onceToken.isExpired()) {
-                                               // AuthPassword.remove(getAttributes(), onceToken);
-                                               return false;
-                                       } else {
-                                               // boolean wasRemoved = AuthPassword.remove(getAttributes(), onceToken);
-                                               return true;
-                                       }
-                                       // TODO delete expired tokens?
-                               } else {
-                                       // TODO implement SHA
-                                       throw new UnsupportedOperationException(
-                                                       "Unsupported authPassword scheme " + authPassword.getAuthScheme());
-                               }
-                       }
-
-                       // Regular password
-//                     byte[] hashedPassword = hash(password, DigestUtils.PASSWORD_SCHEME_PBKDF2_SHA256);
-                       if (hasCredential(LdapAttrs.userPassword.name(), DirectoryDigestUtils.charsToBytes(password)))
-                               return true;
-                       return false;
-               }
-
-               Object storedValue = getCredentials().get(key);
-               if (storedValue == null || value == null)
-                       return false;
-               if (!(value instanceof String || value instanceof byte[]))
-                       return false;
-               if (storedValue instanceof String && value instanceof String)
-                       return storedValue.equals(value);
-               if (storedValue instanceof byte[] && value instanceof byte[]) {
-                       String storedBase64 = new String((byte[]) storedValue, US_ASCII);
-                       String passwordScheme = null;
-                       if (storedBase64.charAt(0) == '{') {
-                               int index = storedBase64.indexOf('}');
-                               if (index > 0) {
-                                       passwordScheme = storedBase64.substring(1, index);
-                                       String storedValueBase64 = storedBase64.substring(index + 1);
-                                       byte[] storedValueBytes = Base64.getDecoder().decode(storedValueBase64);
-                                       char[] passwordValue = DirectoryDigestUtils.bytesToChars((byte[]) value);
-                                       byte[] valueBytes;
-                                       if (DirectoryDigestUtils.PASSWORD_SCHEME_SHA.equals(passwordScheme)) {
-                                               valueBytes = DirectoryDigestUtils.toPasswordScheme(passwordScheme, passwordValue, null, null,
-                                                               null);
-                                       } else if (DirectoryDigestUtils.PASSWORD_SCHEME_PBKDF2_SHA256.equals(passwordScheme)) {
-                                               // see https://www.thesubtlety.com/post/a-389-ds-pbkdf2-password-checker/
-                                               byte[] iterationsArr = Arrays.copyOfRange(storedValueBytes, 0, 4);
-                                               BigInteger iterations = new BigInteger(iterationsArr);
-                                               byte[] salt = Arrays.copyOfRange(storedValueBytes, iterationsArr.length,
-                                                               iterationsArr.length + 64);
-                                               byte[] keyArr = Arrays.copyOfRange(storedValueBytes, iterationsArr.length + salt.length,
-                                                               storedValueBytes.length);
-                                               int keyLengthBits = keyArr.length * 8;
-                                               valueBytes = DirectoryDigestUtils.toPasswordScheme(passwordScheme, passwordValue, salt,
-                                                               iterations.intValue(), keyLengthBits);
-                                       } else {
-                                               throw new UnsupportedOperationException("Unknown password scheme " + passwordScheme);
-                                       }
-                                       return Arrays.equals(storedValueBytes, valueBytes);
-                               }
-                       }
-               }
-//             if (storedValue instanceof byte[] && value instanceof byte[]) {
-//                     return Arrays.equals((byte[]) storedValue, (byte[]) value);
-//             }
-               return false;
-       }
-
-       /** Hash the password */
-       private static byte[] sha1hash(char[] password) {
-               byte[] hashedPassword = ("{SHA}" + Base64.getEncoder()
-                               .encodeToString(DirectoryDigestUtils.sha1(DirectoryDigestUtils.charsToBytes(password))))
-                               .getBytes(StandardCharsets.UTF_8);
-               return hashedPassword;
-       }
-
-       public AbstractLdapDirectory getDirectory() {
-               return directory;
-       }
-
-       public LdapDirectoryDao getDirectoryDao() {
-               return directory.getDirectoryDao();
-       }
-
-       @Override
-       public int hashCode() {
-               return dn.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (this == obj)
-                       return true;
-               if (obj instanceof LdapEntry) {
-                       LdapEntry that = (LdapEntry) obj;
-                       return this.dn.equals(that.getDn());
-               }
-               return false;
-       }
-
-       @Override
-       public String toString() {
-               return dn.toString();
-       }
-
-       private static boolean isAsciiPrintable(String str) {
-               if (str == null) {
-                       return false;
-               }
-               int sz = str.length();
-               for (int i = 0; i < sz; i++) {
-                       if (isAsciiPrintable(str.charAt(i)) == false) {
-                               return false;
-                       }
-               }
-               return true;
-       }
-
-       private static boolean isAsciiPrintable(char ch) {
-               return ch >= 32 && ch < 127;
-       }
-
-       protected class AttributeDictionary extends Dictionary<String, Object> {
-               private final List<String> effectiveKeys = new ArrayList<String>();
-               private final List<String> attrFilter;
-               private final Boolean includeFilter;
-
-               public AttributeDictionary(Boolean credentials) {
-                       this.attrFilter = getDirectory().getCredentialAttributeIds();
-                       this.includeFilter = credentials;
-                       try {
-                               NamingEnumeration<String> ids = getAttributes().getIDs();
-                               while (ids.hasMore()) {
-                                       String id = ids.next();
-                                       if (credentials && attrFilter.contains(id))
-                                               effectiveKeys.add(id);
-                                       else if (!credentials && !attrFilter.contains(id))
-                                               effectiveKeys.add(id);
-                               }
-                       } catch (NamingException e) {
-                               throw new IllegalStateException("Cannot initialise attribute dictionary", e);
-                       }
-                       if (!credentials)
-                               effectiveKeys.add(LdapAttrs.objectClasses.name());
-               }
-
-               @Override
-               public int size() {
-                       return effectiveKeys.size();
-               }
-
-               @Override
-               public boolean isEmpty() {
-                       return effectiveKeys.size() == 0;
-               }
-
-               @Override
-               public Enumeration<String> keys() {
-                       return Collections.enumeration(effectiveKeys);
-               }
-
-               @Override
-               public Enumeration<Object> elements() {
-                       final Iterator<String> it = effectiveKeys.iterator();
-                       return new Enumeration<Object>() {
-
-                               @Override
-                               public boolean hasMoreElements() {
-                                       return it.hasNext();
-                               }
-
-                               @Override
-                               public Object nextElement() {
-                                       String key = it.next();
-                                       return get(key);
-                               }
-
-                       };
-               }
-
-               @Override
-               public Object get(Object key) {
-                       try {
-                               Attribute attr = !key.equals(LdapAttrs.objectClasses.name()) ? getAttributes().get(key.toString())
-                                               : getAttributes().get(LdapAttrs.objectClass.name());
-                               if (attr == null)
-                                       return null;
-                               Object value = attr.get();
-                               if (value instanceof byte[]) {
-                                       if (key.equals(LdapAttrs.userPassword.name()))
-                                               // TODO other cases (certificates, images)
-                                               return value;
-                                       value = new String((byte[]) value, StandardCharsets.UTF_8);
-                               }
-                               if (attr.size() == 1)
-                                       return value;
-                               // special case for object class
-                               if (key.equals(LdapAttrs.objectClass.name())) {
-                                       // TODO support multiple object classes
-                                       NamingEnumeration<?> en = attr.getAll();
-                                       String first = null;
-                                       attrs: while (en.hasMore()) {
-                                               String v = en.next().toString();
-                                               if (v.equalsIgnoreCase(LdapObjs.top.name()))
-                                                       continue attrs;
-                                               if (first == null)
-                                                       first = v;
-                                               if (v.equalsIgnoreCase(getDirectory().getUserObjectClass()))
-                                                       return getDirectory().getUserObjectClass();
-                                               else if (v.equalsIgnoreCase(getDirectory().getGroupObjectClass()))
-                                                       return getDirectory().getGroupObjectClass();
-                                       }
-                                       if (first != null)
-                                               return first;
-                                       throw new IllegalStateException("Cannot find objectClass in " + value);
-                               } else {
-                                       NamingEnumeration<?> en = attr.getAll();
-                                       StringJoiner values = new StringJoiner("\n");
-                                       while (en.hasMore()) {
-                                               String v = en.next().toString();
-                                               values.add(v);
-                                       }
-                                       return values.toString();
-                               }
-//                             else
-//                                     return value;
-                       } catch (NamingException e) {
-                               throw new IllegalStateException("Cannot get value for attribute " + key, e);
-                       }
-               }
-
-               @Override
-               public Object put(String key, Object value) {
-                       Objects.requireNonNull(value, "Value for key " + key + " is null");
-                       try {
-                               if (key == null) {
-                                       // FIXME remove this "feature", a key should be specified
-                                       // TODO persist to other sources (like PKCS12)
-                                       char[] password = DirectoryDigestUtils.bytesToChars(value);
-                                       byte[] hashedPassword = sha1hash(password);
-                                       return put(LdapAttrs.userPassword.name(), hashedPassword);
-                               }
-                               if (key.startsWith("X-")) {
-                                       return put(LdapAttrs.authPassword.name(), value);
-                               }
-
-                               // start editing
-                               getDirectory().checkEdit();
-                               if (!isEditing())
-                                       startEditing();
-
-                               // object classes special case.
-                               if (key.equals(LdapAttrs.objectClasses.name())) {
-                                       Attribute attribute = new BasicAttribute(LdapAttrs.objectClass.name());
-                                       String[] objectClasses = value.toString().split("\n");
-                                       for (String objectClass : objectClasses) {
-                                               if (objectClass.trim().equals(""))
-                                                       continue;
-                                               attribute.add(objectClass);
-                                       }
-                                       Attribute previousAttribute = getModifiedAttributes().put(attribute);
-                                       if (previousAttribute != null)
-                                               return previousAttribute.get();
-                                       else
-                                               return null;
-                               }
-
-                               if (!(value instanceof String || value instanceof byte[]))
-                                       throw new IllegalArgumentException("Value must be String or byte[]");
-
-                               if (includeFilter && !attrFilter.contains(key))
-                                       throw new IllegalArgumentException("Key " + key + " not included");
-                               else if (!includeFilter && attrFilter.contains(key))
-                                       throw new IllegalArgumentException("Key " + key + " excluded");
-
-                               Attribute attribute = getModifiedAttributes().get(key.toString());
-                               // if (attribute == null) // block unit tests
-                               attribute = new BasicAttribute(key.toString());
-                               if (value instanceof String && !isAsciiPrintable(((String) value)))
-                                       attribute.add(((String) value).getBytes(StandardCharsets.UTF_8));
-                               else
-                                       attribute.add(value);
-                               Attribute previousAttribute = getModifiedAttributes().put(attribute);
-                               if (previousAttribute != null)
-                                       return previousAttribute.get();
-                               else
-                                       return null;
-                       } catch (NamingException e) {
-                               throw new IllegalStateException("Cannot get value for attribute " + key, e);
-                       }
-               }
-
-               @Override
-               public Object remove(Object key) {
-                       getDirectory().checkEdit();
-                       if (!isEditing())
-                               startEditing();
-
-                       if (includeFilter && !attrFilter.contains(key))
-                               throw new IllegalArgumentException("Key " + key + " not included");
-                       else if (!includeFilter && attrFilter.contains(key))
-                               throw new IllegalArgumentException("Key " + key + " excluded");
-
-                       try {
-                               Attribute attr = getModifiedAttributes().remove(key.toString());
-                               if (attr != null)
-                                       return attr.get();
-                               else
-                                       return null;
-                       } catch (NamingException e) {
-                               throw new IllegalStateException("Cannot remove attribute " + key, e);
-                       }
-               }
-
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/IpaUtils.java b/org.argeo.util/src/org/argeo/util/directory/ldap/IpaUtils.java
deleted file mode 100644 (file)
index 68b4086..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.dns.DnsBrowser;
-
-/** Free IPA specific conventions. */
-public class IpaUtils {
-       public final static String IPA_USER_BASE = "cn=users";
-       public final static String IPA_GROUP_BASE = "cn=groups";
-       public final static String IPA_ROLE_BASE = "cn=roles";
-       public final static String IPA_SERVICE_BASE = "cn=services,cn=accounts";
-
-       public final static Rdn IPA_ACCOUNTS_RDN;
-       static {
-               try {
-                       IPA_ACCOUNTS_RDN = new Rdn(LdapAttrs.cn.name(), "accounts");
-               } catch (InvalidNameException e) {
-                       // should not happen
-                       throw new IllegalStateException(e);
-               }
-       }
-
-       private final static String KRB_PRINCIPAL_NAME = LdapAttrs.krbPrincipalName.name().toLowerCase();
-
-       public final static String IPA_USER_DIRECTORY_CONFIG = DirectoryConf.userBase + "=" + IPA_USER_BASE + "&"
-                       + DirectoryConf.groupBase + "=" + IPA_GROUP_BASE + "&" + DirectoryConf.systemRoleBase + "=" + IPA_ROLE_BASE
-                       + "&" + DirectoryConf.readOnly + "=true";
-
-       @Deprecated
-       static String domainToUserDirectoryConfigPath(String realm) {
-               return domainToBaseDn(realm) + "?" + IPA_USER_DIRECTORY_CONFIG + "&" + DirectoryConf.realm.name() + "=" + realm;
-       }
-
-       public static void addIpaConfig(String realm, Dictionary<String, Object> properties) {
-               properties.put(DirectoryConf.baseDn.name(), domainToBaseDn(realm));
-               properties.put(DirectoryConf.realm.name(), realm);
-               properties.put(DirectoryConf.userBase.name(), IPA_USER_BASE);
-               properties.put(DirectoryConf.groupBase.name(), IPA_GROUP_BASE);
-               properties.put(DirectoryConf.systemRoleBase.name(), IPA_ROLE_BASE);
-               properties.put(DirectoryConf.readOnly.name(), Boolean.TRUE.toString());
-       }
-
-       public static String domainToBaseDn(String domain) {
-               String[] dcs = domain.split("\\.");
-               StringBuilder sb = new StringBuilder();
-               for (int i = 0; i < dcs.length; i++) {
-                       if (i != 0)
-                               sb.append(',');
-                       String dc = dcs[i];
-                       sb.append(LdapAttrs.dc.name()).append('=').append(dc.toLowerCase());
-               }
-               return sb.toString();
-       }
-
-       public static LdapName kerberosToDn(String kerberosName) {
-               String[] kname = kerberosName.split("@");
-               String username = kname[0];
-               String baseDn = domainToBaseDn(kname[1]);
-               String dn;
-               if (!username.contains("/"))
-                       dn = LdapAttrs.uid + "=" + username + "," + IPA_USER_BASE + "," + IPA_ACCOUNTS_RDN + "," + baseDn;
-               else
-                       dn = KRB_PRINCIPAL_NAME + "=" + kerberosName + "," + IPA_SERVICE_BASE + "," + baseDn;
-               try {
-                       return new LdapName(dn);
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Badly formatted name for " + kerberosName + ": " + dn);
-               }
-       }
-
-       private IpaUtils() {
-
-       }
-
-       public static String kerberosDomainFromDns() {
-               String kerberosDomain;
-               try (DnsBrowser dnsBrowser = new DnsBrowser()) {
-                       InetAddress localhost = InetAddress.getLocalHost();
-                       String hostname = localhost.getHostName();
-                       String dnsZone = hostname.substring(hostname.indexOf('.') + 1);
-                       kerberosDomain = dnsBrowser.getRecord("_kerberos." + dnsZone, "TXT");
-                       return kerberosDomain;
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot determine Kerberos domain from DNS", e);
-               }
-
-       }
-
-       public static Dictionary<String, Object> convertIpaUri(URI uri) {
-               String path = uri.getPath();
-               String kerberosRealm;
-               if (path == null || path.length() <= 1) {
-                       kerberosRealm = kerberosDomainFromDns();
-               } else {
-                       kerberosRealm = path.substring(1);
-               }
-
-               if (kerberosRealm == null)
-                       throw new IllegalStateException("No Kerberos domain available for " + uri);
-               // TODO intergrate CA certificate in truststore
-               // String schemeToUse = SCHEME_LDAPS;
-               String schemeToUse = DirectoryConf.SCHEME_LDAP;
-               List<String> ldapHosts;
-               String ldapHostsStr = uri.getHost();
-               if (ldapHostsStr == null || ldapHostsStr.trim().equals("")) {
-                       try (DnsBrowser dnsBrowser = new DnsBrowser()) {
-                               ldapHosts = dnsBrowser.getSrvRecordsAsHosts("_ldap._tcp." + kerberosRealm.toLowerCase(),
-                                               schemeToUse.equals(DirectoryConf.SCHEME_LDAP) ? true : false);
-                               if (ldapHosts == null || ldapHosts.size() == 0) {
-                                       throw new IllegalStateException("Cannot configure LDAP for IPA " + uri);
-                               } else {
-                                       ldapHostsStr = ldapHosts.get(0);
-                               }
-                       } catch (IOException e) {
-                               throw new IllegalStateException("Cannot convert IPA uri " + uri, e);
-                       }
-               } else {
-                       ldapHosts = new ArrayList<>();
-                       ldapHosts.add(ldapHostsStr);
-               }
-
-               StringBuilder uriStr = new StringBuilder();
-               try {
-                       for (String host : ldapHosts) {
-                               URI convertedUri = new URI(schemeToUse + "://" + host + "/");
-                               uriStr.append(convertedUri).append(' ');
-                       }
-               } catch (URISyntaxException e) {
-                       throw new IllegalStateException("Cannot convert IPA uri " + uri, e);
-               }
-
-               Hashtable<String, Object> res = new Hashtable<>();
-               res.put(DirectoryConf.uri.name(), uriStr.toString());
-               addIpaConfig(kerberosRealm, res);
-               return res;
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapConnection.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapConnection.java
deleted file mode 100644 (file)
index 748efe3..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import javax.naming.CommunicationException;
-import javax.naming.Context;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.InitialLdapContext;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.transaction.WorkingCopy;
-
-/** A synchronized wrapper for a single {@link InitialLdapContext}. */
-// TODO implement multiple contexts and connection pooling.
-public class LdapConnection {
-       private InitialLdapContext initialLdapContext = null;
-
-       public LdapConnection(String url, Dictionary<String, ?> properties) {
-               try {
-                       Hashtable<String, Object> connEnv = new Hashtable<String, Object>();
-                       connEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
-                       connEnv.put(Context.PROVIDER_URL, url);
-                       connEnv.put("java.naming.ldap.attributes.binary", LdapAttrs.userPassword.name());
-                       // use pooling in order to avoid connection timeout
-//                     connEnv.put("com.sun.jndi.ldap.connect.pool", "true");
-//                     connEnv.put("com.sun.jndi.ldap.connect.pool.timeout", 300000);
-
-                       initialLdapContext = new InitialLdapContext(connEnv, null);
-                       // StartTlsResponse tls = (StartTlsResponse) ctx
-                       // .extendedOperation(new StartTlsRequest());
-                       // tls.negotiate();
-                       Object securityAuthentication = properties.get(Context.SECURITY_AUTHENTICATION);
-                       if (securityAuthentication != null)
-                               initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, securityAuthentication);
-                       else
-                               initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
-                       Object principal = properties.get(Context.SECURITY_PRINCIPAL);
-                       if (principal != null) {
-                               initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, principal.toString());
-                               Object creds = properties.get(Context.SECURITY_CREDENTIALS);
-                               if (creds != null) {
-                                       initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, creds.toString());
-                               }
-                       }
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot connect to LDAP", e);
-               }
-
-       }
-
-       public void init() {
-
-       }
-
-       public void destroy() {
-               try {
-                       // tls.close();
-                       initialLdapContext.close();
-                       initialLdapContext = null;
-               } catch (NamingException e) {
-                       e.printStackTrace();
-               }
-       }
-
-       protected InitialLdapContext getLdapContext() {
-               return initialLdapContext;
-       }
-
-       protected void reconnect() throws NamingException {
-               initialLdapContext.reconnect(initialLdapContext.getConnectControls());
-       }
-
-       public synchronized NamingEnumeration<SearchResult> search(LdapName searchBase, String searchFilter,
-                       SearchControls searchControls) throws NamingException {
-               NamingEnumeration<SearchResult> results;
-               try {
-                       results = getLdapContext().search(searchBase, searchFilter, searchControls);
-               } catch (CommunicationException e) {
-                       reconnect();
-                       results = getLdapContext().search(searchBase, searchFilter, searchControls);
-               }
-               return results;
-       }
-
-       public synchronized Attributes getAttributes(LdapName name) throws NamingException {
-               try {
-                       return getLdapContext().getAttributes(name);
-               } catch (CommunicationException e) {
-                       reconnect();
-                       return getLdapContext().getAttributes(name);
-               }
-       }
-
-       public synchronized boolean entryExists(LdapName name) throws NamingException {
-               String[] noAttrOID = new String[] { "1.1" };
-               try {
-                       getLdapContext().getAttributes(name, noAttrOID);
-                       return true;
-               } catch (CommunicationException e) {
-                       reconnect();
-                       getLdapContext().getAttributes(name, noAttrOID);
-                       return true;
-               } catch (NameNotFoundException e) {
-                       return false;
-               }
-       }
-
-       public synchronized void prepareChanges(WorkingCopy<?, ?, LdapName> wc) throws NamingException {
-               // make sure connection will work
-               reconnect();
-
-               // delete
-               for (LdapName dn : wc.getDeletedData().keySet()) {
-                       if (!entryExists(dn))
-                               throw new IllegalStateException("User to delete no found " + dn);
-               }
-               // add
-               for (LdapName dn : wc.getNewData().keySet()) {
-                       if (entryExists(dn))
-                               throw new IllegalStateException("User to create found " + dn);
-               }
-               // modify
-               for (LdapName dn : wc.getModifiedData().keySet()) {
-                       if (!wc.getNewData().containsKey(dn) && !entryExists(dn))
-                               throw new IllegalStateException("User to modify not found " + dn);
-               }
-
-       }
-
-//     protected boolean entryExists(LdapName dn) throws NamingException {
-//             try {
-//                     return getAttributes(dn).size() != 0;
-//             } catch (NameNotFoundException e) {
-//                     return false;
-//             }
-//     }
-
-       public synchronized void commitChanges(LdapEntryWorkingCopy wc) throws NamingException {
-               // delete
-               for (LdapName dn : wc.getDeletedData().keySet()) {
-                       getLdapContext().destroySubcontext(dn);
-               }
-               // add
-               for (LdapName dn : wc.getNewData().keySet()) {
-                       LdapEntry user = wc.getNewData().get(dn);
-                       getLdapContext().createSubcontext(dn, user.getAttributes());
-               }
-               // modify
-               for (LdapName dn : wc.getModifiedData().keySet()) {
-                       Attributes modifiedAttrs = wc.getModifiedData().get(dn);
-                       getLdapContext().modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, modifiedAttrs);
-               }
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java
deleted file mode 100644 (file)
index 0f6e324..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import static org.argeo.util.naming.LdapAttrs.objectClass;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.naming.AuthenticationNotSupportedException;
-import javax.naming.Binding;
-import javax.naming.InvalidNameException;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-
-/** A user admin based on a LDAP server. */
-public class LdapDao extends AbstractLdapDirectoryDao {
-       private LdapConnection ldapConnection;
-
-       public LdapDao(AbstractLdapDirectory directory) {
-               super(directory);
-       }
-
-       @Override
-       public void init() {
-               ldapConnection = new LdapConnection(getDirectory().getUri().toString(), getDirectory().cloneConfigProperties());
-       }
-
-       public void destroy() {
-               ldapConnection.destroy();
-       }
-
-       @Override
-       public boolean checkConnection() {
-               try {
-                       return ldapConnection.entryExists(getDirectory().getBaseDn());
-               } catch (NamingException e) {
-                       return false;
-               }
-       }
-
-       @Override
-       public boolean entryExists(LdapName dn) {
-               try {
-                       return ldapConnection.entryExists(dn);
-               } catch (NameNotFoundException e) {
-                       return false;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot check " + dn, e);
-               }
-       }
-
-       @Override
-       public LdapEntry doGetEntry(LdapName name) throws NameNotFoundException {
-//             if (!entryExists(name))
-//                     throw new NameNotFoundException(name + " was not found in " + getDirectory().getBaseDn());
-               try {
-                       Attributes attrs = ldapConnection.getAttributes(name);
-
-                       LdapEntry res;
-                       Rdn technicalRdn = LdapNameUtils.getParentRdn(name);
-                       if (getDirectory().getGroupBaseRdn().equals(technicalRdn)) {
-                               if (attrs.size() == 0) {// exists but not accessible
-                                       attrs = new BasicAttributes();
-                                       attrs.put(LdapAttrs.objectClass.name(), LdapObjs.top.name());
-                                       attrs.put(LdapAttrs.objectClass.name(), getDirectory().getGroupObjectClass());
-                               }
-                               res = newGroup(name);
-                       } else if (getDirectory().getSystemRoleBaseRdn().equals(technicalRdn)) {
-                               if (attrs.size() == 0) {// exists but not accessible
-                                       attrs = new BasicAttributes();
-                                       attrs.put(LdapAttrs.objectClass.name(), LdapObjs.top.name());
-                                       attrs.put(LdapAttrs.objectClass.name(), getDirectory().getGroupObjectClass());
-                               }
-                               res = newGroup(name);
-                       } else if (getDirectory().getUserBaseRdn().equals(technicalRdn)) {
-                               if (attrs.size() == 0) {// exists but not accessible
-                                       attrs = new BasicAttributes();
-                                       attrs.put(LdapAttrs.objectClass.name(), LdapObjs.top.name());
-                                       attrs.put(LdapAttrs.objectClass.name(), getDirectory().getUserObjectClass());
-                               }
-                               res = newUser(name);
-                       } else {
-                               res = new DefaultLdapEntry(getDirectory(), name);
-                       }
-                       return res;
-               } catch (NameNotFoundException e) {
-                       throw e;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot retrieve entry " + name, e);
-               }
-       }
-
-       @Override
-       public Attributes doGetAttributes(LdapName name) {
-               try {
-                       Attributes attrs = ldapConnection.getAttributes(name);
-                       return attrs;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get attributes for " + name);
-               }
-       }
-
-       @Override
-       public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
-               ArrayList<LdapEntry> res = new ArrayList<>();
-               try {
-                       String searchFilter = f != null ? f.toString()
-                                       : "(|(" + objectClass.name() + "=" + getDirectory().getUserObjectClass() + ")(" + objectClass.name()
-                                                       + "=" + getDirectory().getGroupObjectClass() + "))";
-                       SearchControls searchControls = new SearchControls();
-                       // only attribute needed is objectClass
-                       searchControls.setReturningAttributes(new String[] { objectClass.name() });
-                       // FIXME make one level consistent with deep
-                       searchControls.setSearchScope(deep ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
-
-                       // LdapName searchBase = getBaseDn();
-                       NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
-
-                       results: while (results.hasMoreElements()) {
-                               SearchResult searchResult = results.next();
-                               Attributes attrs = searchResult.getAttributes();
-                               Attribute objectClassAttr = attrs.get(objectClass.name());
-                               LdapName dn = toDn(searchBase, searchResult);
-                               LdapEntry role;
-                               if (objectClassAttr.contains(getDirectory().getGroupObjectClass())
-                                               || objectClassAttr.contains(getDirectory().getGroupObjectClass().toLowerCase()))
-                                       role = newGroup(dn);
-                               else if (objectClassAttr.contains(getDirectory().getUserObjectClass())
-                                               || objectClassAttr.contains(getDirectory().getUserObjectClass().toLowerCase()))
-                                       role = newUser(dn);
-                               else {
-//                                     log.warn("Unsupported LDAP type for " + searchResult.getName());
-                                       continue results;
-                               }
-                               res.add(role);
-                       }
-                       return res;
-               } catch (AuthenticationNotSupportedException e) {
-                       // ignore (typically an unsupported anonymous bind)
-                       // TODO better logging
-                       return res;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get roles for filter " + f, e);
-               }
-       }
-
-       private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
-               return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
-       }
-
-       @Override
-       public List<LdapName> getDirectGroups(LdapName dn) {
-               List<LdapName> directGroups = new ArrayList<LdapName>();
-               try {
-                       String searchFilter = "(&(" + objectClass + "=" + getDirectory().getGroupObjectClass() + ")("
-                                       + getDirectory().getMemberAttributeId() + "=" + dn + "))";
-
-                       SearchControls searchControls = new SearchControls();
-                       searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
-                       LdapName searchBase = getDirectory().getBaseDn();
-                       NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
-
-                       while (results.hasMoreElements()) {
-                               SearchResult searchResult = (SearchResult) results.nextElement();
-                               directGroups.add(toDn(searchBase, searchResult));
-                       }
-                       return directGroups;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot populate direct members of " + dn, e);
-               }
-       }
-
-       @Override
-       public void prepare(LdapEntryWorkingCopy wc) {
-               try {
-                       ldapConnection.prepareChanges(wc);
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot prepare LDAP", e);
-               }
-       }
-
-       @Override
-       public void commit(LdapEntryWorkingCopy wc) {
-               try {
-                       ldapConnection.commitChanges(wc);
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot commit LDAP", e);
-               }
-       }
-
-       @Override
-       public void rollback(LdapEntryWorkingCopy wc) {
-               // prepare not impacting
-       }
-
-       /*
-        * HIERARCHY
-        */
-
-       @Override
-       public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
-               List<HierarchyUnit> res = new ArrayList<>();
-               try {
-                       String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
-                                       + "=" + LdapObjs.organization.name() + "))";
-//                     String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
-//                                     + "=" + LdapObjs.organization.name() + ")(cn=accounts)(cn=users)(cn=groups))";
-
-                       SearchControls searchControls = new SearchControls();
-                       searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
-                       // no attributes needed
-                       searchControls.setReturningAttributes(new String[0]);
-
-                       NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
-
-                       while (results.hasMoreElements()) {
-                               SearchResult searchResult = (SearchResult) results.nextElement();
-                               LdapName dn = toDn(searchBase, searchResult);
-//                             Attributes attrs = searchResult.getAttributes();
-                               LdapHierarchyUnit hierarchyUnit = new LdapHierarchyUnit(getDirectory(), dn);
-                               if (functionalOnly) {
-                                       if (hierarchyUnit.isFunctional())
-                                               res.add(hierarchyUnit);
-                               } else {
-                                       res.add(hierarchyUnit);
-                               }
-                       }
-                       return res;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get direct hierarchy units ", e);
-               }
-       }
-
-       @Override
-       public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
-               try {
-                       if (getDirectory().getBaseDn().equals(dn))
-                               return getDirectory();
-                       if (!dn.startsWith(getDirectory().getBaseDn()))
-                               throw new IllegalArgumentException(dn + " does not start with base DN " + getDirectory().getBaseDn());
-                       if (!ldapConnection.entryExists(dn))
-                               return null;
-                       return new LdapHierarchyUnit(getDirectory(), dn);
-               } catch (NameNotFoundException e) {
-                       return null;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
-               }
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDirectoryDao.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDirectoryDao.java
deleted file mode 100644 (file)
index f317800..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.util.List;
-
-import javax.naming.NameNotFoundException;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.transaction.WorkingCopyProcessor;
-
-public interface LdapDirectoryDao extends WorkingCopyProcessor<LdapEntryWorkingCopy> {
-       boolean checkConnection();
-
-       boolean entryExists(LdapName dn);
-
-       LdapEntry doGetEntry(LdapName name) throws NameNotFoundException;
-
-       Attributes doGetAttributes(LdapName name);
-
-       List<LdapEntry> doGetEntries(LdapName searchBase, String filter, boolean deep);
-
-       List<LdapName> getDirectGroups(LdapName dn);
-
-       Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly);
-
-       HierarchyUnit doGetHierarchyUnit(LdapName dn);
-
-       LdapEntry newUser(LdapName name);
-
-       LdapEntry newGroup(LdapName name);
-
-       void init();
-
-       void destroy();
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapEntry.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapEntry.java
deleted file mode 100644 (file)
index 4657c87..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Dictionary;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import java.util.StringJoiner;
-import java.util.TreeSet;
-
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.naming.LdapAttrs;
-
-/** An LDAP entry. */
-public interface LdapEntry {
-       LdapName getDn();
-
-       Attributes getAttributes();
-
-       void publishAttributes(Attributes modifiedAttributes);
-
-       List<LdapName> getReferences(String attributeId);
-
-       Dictionary<String, Object> getProperties();
-
-       boolean hasCredential(String key, Object value);
-
-       /*
-        * UTILITIES
-        */
-       /**
-        * Convert a collection of object classes to the format expected by an LDAP
-        * backend.
-        */
-       public static void addObjectClasses(Dictionary<String, Object> properties, Collection<String> objectClasses) {
-               String value = properties.get(LdapAttrs.objectClasses.name()).toString();
-               Set<String> currentObjectClasses = new TreeSet<>(Arrays.asList(value.toString().split("\n")));
-               currentObjectClasses.addAll(objectClasses);
-               StringJoiner values = new StringJoiner("\n");
-               currentObjectClasses.forEach((s) -> values.add(s));
-               properties.put(LdapAttrs.objectClasses.name(), values.toString());
-       }
-
-       public static Object getLocalized(Dictionary<String, Object> properties, String key, Locale locale) {
-               if (locale == null)
-                       return null;
-               Object value = null;
-               value = properties.get(key + ";lang-" + locale.getLanguage() + "-" + locale.getCountry());
-               if (value == null)
-                       value = properties.get(key + ";lang-" + locale.getLanguage());
-               return value;
-       }
-
-       public static String toLocalizedKey(String key, Locale locale) {
-               String country = locale.getCountry();
-               if ("".equals(country)) {
-                       return key + ";lang-" + locale.getLanguage();
-               } else {
-                       return key + ";lang-" + locale.getLanguage() + "-" + locale.getCountry();
-               }
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapEntryWorkingCopy.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapEntryWorkingCopy.java
deleted file mode 100644 (file)
index 381c11b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.transaction.AbstractWorkingCopy;
-
-/** Working copy for a user directory being edited. */
-public class LdapEntryWorkingCopy extends AbstractWorkingCopy<LdapEntry, Attributes, LdapName> {
-       @Override
-       protected LdapName getId(LdapEntry entry) {
-               return entry.getDn();
-       }
-
-       @Override
-       protected Attributes cloneAttributes(LdapEntry entry) {
-               return (Attributes) entry.getAttributes().clone();
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapHierarchyUnit.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapHierarchyUnit.java
deleted file mode 100644 (file)
index 961f2e3..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.util.Locale;
-
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.argeo.util.directory.HierarchyUnit;
-
-/** LDIF/LDAP based implementation of {@link HierarchyUnit}. */
-public class LdapHierarchyUnit extends DefaultLdapEntry implements HierarchyUnit {
-       private final boolean functional;
-
-       public LdapHierarchyUnit(AbstractLdapDirectory directory, LdapName dn) {
-               super(directory, dn);
-
-               Rdn rdn = LdapNameUtils.getLastRdn(dn);
-               functional = !(directory.getUserBaseRdn().equals(rdn) || directory.getGroupBaseRdn().equals(rdn)
-                               || directory.getSystemRoleBaseRdn().equals(rdn));
-       }
-
-       @Override
-       public HierarchyUnit getParent() {
-               return getDirectoryDao().doGetHierarchyUnit(LdapNameUtils.getParent(getDn()));
-       }
-
-       @Override
-       public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
-               return getDirectoryDao().doGetDirectHierarchyUnits(getDn(), functionalOnly);
-       }
-
-       @Override
-       public boolean isFunctional() {
-               return functional;
-       }
-
-       @Override
-       public String getHierarchyUnitName() {
-               String name = LdapNameUtils.getLastRdnValue(getDn());
-               // TODO check ou, o, etc.
-               return name;
-       }
-
-       @Override
-       public String getHierarchyUnitLabel(Locale locale) {
-               String key = LdapNameUtils.getLastRdn(getDn()).getType();
-               Object value = LdapEntry.getLocalized(getProperties(), key, locale);
-               if (value == null)
-                       value = getHierarchyUnitName();
-               assert value != null;
-               return value.toString();
-       }
-
-       @Override
-       public String getBase() {
-               return getDn().toString();
-       }
-
-       @Override
-       public String toString() {
-               return "Hierarchy Unit " + getDn().toString();
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapNameUtils.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapNameUtils.java
deleted file mode 100644 (file)
index 88d3175..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-/** Utilities to simplify using {@link LdapName}. */
-public class LdapNameUtils {
-
-       public static LdapName relativeName(LdapName prefix, LdapName dn) {
-               try {
-                       if (!dn.startsWith(prefix))
-                               throw new IllegalArgumentException("Prefix " + prefix + " not consistent with " + dn);
-                       LdapName res = (LdapName) dn.clone();
-                       for (int i = 0; i < prefix.size(); i++) {
-                               res.remove(0);
-                       }
-                       return res;
-               } catch (InvalidNameException e) {
-                       throw new IllegalStateException("Cannot find realtive name", e);
-               }
-       }
-
-       public static LdapName getParent(LdapName dn) {
-               try {
-                       LdapName parent = (LdapName) dn.clone();
-                       parent.remove(parent.size() - 1);
-                       return parent;
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Cannot get parent of " + dn, e);
-               }
-       }
-
-       public static Rdn getParentRdn(LdapName dn) {
-               if (dn.size() < 2)
-                       throw new IllegalArgumentException(dn + " has no parent");
-               Rdn parentRdn = dn.getRdn(dn.size() - 2);
-               return parentRdn;
-       }
-
-       public static LdapName toLdapName(String distinguishedName) {
-               try {
-                       return new LdapName(distinguishedName);
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Cannot parse " + distinguishedName + " as LDAP name", e);
-               }
-       }
-
-       public static Rdn getLastRdn(LdapName dn) {
-               return dn.getRdn(dn.size() - 1);
-       }
-
-       public static String getLastRdnAsString(LdapName dn) {
-               return getLastRdn(dn).toString();
-       }
-
-       public static String getLastRdnValue(String dn) {
-               return getLastRdnValue(toLdapName(dn));
-       }
-
-       public static String getLastRdnValue(LdapName dn) {
-               return getLastRdn(dn).getValue().toString();
-       }
-
-       /** singleton */
-       private LdapNameUtils() {
-
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java
deleted file mode 100644 (file)
index c200faa..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import static org.argeo.util.naming.LdapAttrs.objectClass;
-import static org.argeo.util.naming.LdapObjs.inetOrgPerson;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.NavigableMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.naming.LdapObjs;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Role;
-
-/** A user admin based on a LDIF files. */
-public class LdifDao extends AbstractLdapDirectoryDao {
-       private NavigableMap<LdapName, LdapEntry> entries = new TreeMap<>();
-       private NavigableMap<LdapName, LdapHierarchyUnit> hierarchy = new TreeMap<>();
-
-       private NavigableMap<LdapName, Attributes> values = new TreeMap<>();
-
-       public LdifDao(AbstractLdapDirectory directory) {
-               super(directory);
-       }
-
-       public void init() {
-               String uri = getDirectory().getUri();
-               if (uri == null)
-                       return;
-               try {
-                       URI u = new URI(uri);
-                       if (u.getScheme().equals("file")) {
-                               File file = new File(u);
-                               if (!file.exists())
-                                       return;
-                       }
-                       load(u.toURL().openStream());
-               } catch (IOException | URISyntaxException e) {
-                       throw new IllegalStateException("Cannot open URL " + getDirectory().getUri(), e);
-               }
-       }
-
-       public void save() {
-               if (getDirectory().getUri() == null)
-                       return; // ignore
-               if (getDirectory().isReadOnly())
-                       throw new IllegalStateException(
-                                       "Cannot save LDIF user admin: " + getDirectory().getUri() + " is read-only");
-               try (FileOutputStream out = new FileOutputStream(new File(new URI(getDirectory().getUri())))) {
-                       save(out);
-               } catch (IOException | URISyntaxException e) {
-                       throw new IllegalStateException("Cannot save user admin to " + getDirectory().getUri(), e);
-               }
-       }
-
-       public void save(OutputStream out) throws IOException {
-               try {
-                       LdifWriter ldifWriter = new LdifWriter(out);
-                       for (LdapName name : hierarchy.keySet())
-                               ldifWriter.writeEntry(name, hierarchy.get(name).getAttributes());
-                       for (LdapName name : entries.keySet())
-                               ldifWriter.writeEntry(name, entries.get(name).getAttributes());
-               } finally {
-                       out.close();
-               }
-       }
-
-       public void load(InputStream in) {
-               try {
-                       entries.clear();
-                       hierarchy.clear();
-
-                       LdifParser ldifParser = new LdifParser();
-                       SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
-                       for (LdapName key : allEntries.keySet()) {
-                               Attributes attributes = allEntries.get(key);
-                               // check for inconsistency
-                               Set<String> lowerCase = new HashSet<String>();
-                               NamingEnumeration<String> ids = attributes.getIDs();
-                               while (ids.hasMoreElements()) {
-                                       String id = ids.nextElement().toLowerCase();
-                                       if (lowerCase.contains(id))
-                                               throw new IllegalStateException(key + " has duplicate id " + id);
-                                       lowerCase.add(id);
-                               }
-
-                               values.put(key, attributes);
-
-                               // analyse object classes
-                               NamingEnumeration<?> objectClasses = attributes.get(objectClass.name()).getAll();
-                               // System.out.println(key);
-                               objectClasses: while (objectClasses.hasMore()) {
-                                       String objectClass = objectClasses.next().toString();
-                                       // System.out.println(" " + objectClass);
-                                       if (objectClass.toLowerCase().equals(inetOrgPerson.name().toLowerCase())) {
-                                               entries.put(key, newUser(key));
-                                               break objectClasses;
-                                       } else if (objectClass.toLowerCase().equals(getDirectory().getGroupObjectClass().toLowerCase())) {
-                                               entries.put(key, newGroup(key));
-                                               break objectClasses;
-                                       } else if (objectClass.equalsIgnoreCase(LdapObjs.organizationalUnit.name())) {
-                                               // TODO skip if it does not contain groups or users
-                                               hierarchy.put(key, new LdapHierarchyUnit(getDirectory(), key));
-                                               break objectClasses;
-                                       }
-                               }
-                       }
-
-               } catch (NamingException | IOException e) {
-                       throw new IllegalStateException("Cannot load user admin service from LDIF", e);
-               }
-       }
-
-       public void destroy() {
-//             if (users == null || groups == null)
-               if (entries == null)
-                       throw new IllegalStateException("User directory " + getDirectory().getBaseDn() + " is already destroyed");
-//             users = null;
-//             groups = null;
-               entries = null;
-       }
-
-       /*
-        * USER ADMIN
-        */
-
-       @Override
-       public LdapEntry doGetEntry(LdapName key) throws NameNotFoundException {
-               if (entries.containsKey(key))
-                       return entries.get(key);
-               throw new NameNotFoundException(key + " not persisted");
-       }
-
-       @Override
-       public Attributes doGetAttributes(LdapName name) {
-               if (!values.containsKey(name))
-                       throw new IllegalStateException(name + " doe not exist in " + getDirectory().getBaseDn());
-               return values.get(name);
-       }
-
-       @Override
-       public boolean checkConnection() {
-               return true;
-       }
-
-       @Override
-       public boolean entryExists(LdapName dn) {
-               return entries.containsKey(dn);// || groups.containsKey(dn);
-       }
-
-       @Override
-       public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
-               Objects.requireNonNull(searchBase);
-               ArrayList<LdapEntry> res = new ArrayList<>();
-               if (f == null && deep && getDirectory().getBaseDn().equals(searchBase)) {
-                       res.addAll(entries.values());
-               } else {
-                       filterRoles(entries, searchBase, f, deep, res);
-               }
-               return res;
-       }
-
-       private void filterRoles(SortedMap<LdapName, ? extends LdapEntry> map, LdapName searchBase, String f, boolean deep,
-                       List<LdapEntry> res) {
-               // FIXME get rid of OSGi references
-               try {
-                       // TODO reduce map with search base ?
-                       Filter filter = f != null ? FrameworkUtil.createFilter(f) : null;
-                       roles: for (LdapEntry user : map.values()) {
-                               LdapName dn = user.getDn();
-                               if (dn.startsWith(searchBase)) {
-                                       if (!deep && dn.size() != (searchBase.size() + 1))
-                                               continue roles;
-                                       if (filter == null)
-                                               res.add(user);
-                                       else {
-                                               if (user instanceof Role) {
-                                                       if (filter.match(((Role) user).getProperties()))
-                                                               res.add(user);
-                                               }
-                                       }
-                               }
-                       }
-               } catch (InvalidSyntaxException e) {
-                       throw new IllegalArgumentException("Cannot create filter " + f, e);
-               }
-
-       }
-
-       @Override
-       public List<LdapName> getDirectGroups(LdapName dn) {
-               List<LdapName> directGroups = new ArrayList<LdapName>();
-               entries: for (LdapName name : entries.keySet()) {
-                       LdapEntry group;
-                       try {
-                               LdapEntry entry = doGetEntry(name);
-                               if (AbstractLdapDirectory.hasObjectClass(entry.getAttributes(), getDirectory().getGroupObjectClass())) {
-                                       group = entry;
-                               } else {
-                                       continue entries;
-                               }
-                       } catch (NameNotFoundException e) {
-                               throw new IllegalArgumentException("Group " + dn + " not found", e);
-                       }
-                       if (group.getReferences(getDirectory().getMemberAttributeId()).contains(dn)) {
-                               directGroups.add(group.getDn());
-                       }
-               }
-               return directGroups;
-       }
-
-       @Override
-       public void prepare(LdapEntryWorkingCopy wc) {
-               // delete
-               for (LdapName dn : wc.getDeletedData().keySet()) {
-                       if (entries.containsKey(dn))
-                               entries.remove(dn);
-                       else
-                               throw new IllegalStateException("User to delete not found " + dn);
-               }
-               // add
-               for (LdapName dn : wc.getNewData().keySet()) {
-                       LdapEntry user = (LdapEntry) wc.getNewData().get(dn);
-                       if (entries.containsKey(dn))
-                               throw new IllegalStateException("User to create found " + dn);
-                       entries.put(dn, user);
-               }
-               // modify
-               for (LdapName dn : wc.getModifiedData().keySet()) {
-                       Attributes modifiedAttrs = wc.getModifiedData().get(dn);
-                       LdapEntry user;
-                       try {
-                               user = doGetEntry(dn);
-                       } catch (NameNotFoundException e) {
-                               throw new IllegalStateException("User to modify no found " + dn, e);
-                       }
-                       if (user == null)
-                               throw new IllegalStateException("User to modify no found " + dn);
-                       user.publishAttributes(modifiedAttrs);
-               }
-       }
-
-       @Override
-       public void commit(LdapEntryWorkingCopy wc) {
-               save();
-       }
-
-       @Override
-       public void rollback(LdapEntryWorkingCopy wc) {
-               init();
-       }
-
-       /*
-        * HIERARCHY
-        */
-       @Override
-       public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
-               if (getDirectory().getBaseDn().equals(dn))
-                       return getDirectory();
-               return hierarchy.get(dn);
-       }
-
-       @Override
-       public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
-               List<HierarchyUnit> res = new ArrayList<>();
-               for (LdapName n : hierarchy.keySet()) {
-                       if (n.size() == searchBase.size() + 1) {
-                               if (n.startsWith(searchBase)) {
-                                       HierarchyUnit hu = hierarchy.get(n);
-                                       if (functionalOnly) {
-                                               if (hu.isFunctional())
-                                                       res.add(hu);
-                                       } else {
-                                               res.add(hu);
-                                       }
-                               }
-                       }
-               }
-               return res;
-       }
-
-       public void scope(LdifDao scoped) {
-               scoped.entries = Collections.unmodifiableNavigableMap(entries);
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdifParser.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdifParser.java
deleted file mode 100644 (file)
index 0022943..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.List;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.naming.InvalidNameException;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.argeo.util.naming.LdapAttrs;
-
-/** Basic LDIF parser. */
-public class LdifParser {
-       private final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
-
-       protected Attributes addAttributes(SortedMap<LdapName, Attributes> res, int lineNumber, LdapName currentDn,
-                       Attributes currentAttributes) {
-               try {
-                       Rdn nameRdn = currentDn.getRdn(currentDn.size() - 1);
-                       Attribute nameAttr = currentAttributes.get(nameRdn.getType());
-                       if (nameAttr == null)
-                               currentAttributes.put(nameRdn.getType(), nameRdn.getValue());
-                       else if (!nameAttr.get().equals(nameRdn.getValue()))
-                               throw new IllegalStateException(
-                                               "Attribute " + nameAttr.getID() + "=" + nameAttr.get() + " not consistent with DN " + currentDn
-                                                               + " (shortly before line " + lineNumber + " in LDIF file)");
-                       Attributes previous = res.put(currentDn, currentAttributes);
-                       return previous;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot add " + currentDn, e);
-               }
-       }
-
-       /** With UTF-8 charset */
-       public SortedMap<LdapName, Attributes> read(InputStream in) throws IOException {
-               try (Reader reader = new InputStreamReader(in, DEFAULT_CHARSET)) {
-                       return read(reader);
-               } finally {
-                       try {
-                               in.close();
-                       } catch (IOException e) {
-                               // silent
-                       }
-               }
-       }
-
-       /** Will close the reader. */
-       public SortedMap<LdapName, Attributes> read(Reader reader) throws IOException {
-               SortedMap<LdapName, Attributes> res = new TreeMap<LdapName, Attributes>();
-               try {
-                       List<String> lines = new ArrayList<>();
-                       try (BufferedReader br = new BufferedReader(reader)) {
-                               String line;
-                               while ((line = br.readLine()) != null) {
-                                       lines.add(line);
-                               }
-                       }
-                       if (lines.size() == 0)
-                               return res;
-                       // add an empty new line since the last line is not checked
-                       if (!lines.get(lines.size() - 1).equals(""))
-                               lines.add("");
-
-                       LdapName currentDn = null;
-                       Attributes currentAttributes = null;
-                       StringBuilder currentEntry = new StringBuilder();
-
-                       readLines: for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
-                               String line = lines.get(lineNumber);
-                               boolean isLastLine = false;
-                               if (lineNumber == lines.size() - 1)
-                                       isLastLine = true;
-                               if (line.startsWith(" ")) {
-                                       currentEntry.append(line.substring(1));
-                                       if (!isLastLine)
-                                               continue readLines;
-                               }
-
-                               if (currentEntry.length() != 0 || isLastLine) {
-                                       // read previous attribute
-                                       StringBuilder attrId = new StringBuilder(8);
-                                       boolean isBase64 = false;
-                                       readAttrId: for (int i = 0; i < currentEntry.length(); i++) {
-                                               char c = currentEntry.charAt(i);
-                                               if (c == ':') {
-                                                       if (i + 1 < currentEntry.length() && currentEntry.charAt(i + 1) == ':')
-                                                               isBase64 = true;
-                                                       currentEntry.delete(0, i + (isBase64 ? 2 : 1));
-                                                       break readAttrId;
-                                               } else {
-                                                       attrId.append(c);
-                                               }
-                                       }
-
-                                       String attributeId = attrId.toString();
-                                       // TODO should we really trim the end of the string as well?
-                                       String cleanValueStr = currentEntry.toString().trim();
-                                       Object attributeValue = isBase64 ? Base64.getDecoder().decode(cleanValueStr) : cleanValueStr;
-
-                                       // manage DN attributes
-                                       if (attributeId.equals(LdapAttrs.DN) || isLastLine) {
-                                               if (currentDn != null) {
-                                                       //
-                                                       // ADD
-                                                       //
-                                                       Attributes previous = addAttributes(res, lineNumber, currentDn, currentAttributes);
-                                                       if (previous != null) {
-//                                                             log.warn("There was already an entry with DN " + currentDn
-//                                                                             + ", which has been discarded by a subsequent one.");
-                                                       }
-                                               }
-
-                                               if (attributeId.equals(LdapAttrs.DN))
-                                                       try {
-                                                               currentDn = new LdapName(attributeValue.toString());
-                                                               currentAttributes = new BasicAttributes(true);
-                                                       } catch (InvalidNameException e) {
-//                                                             log.error(attributeValue + " not a valid DN, skipping the entry.");
-                                                               currentDn = null;
-                                                               currentAttributes = null;
-                                                       }
-                                       }
-
-                                       // store attribute
-                                       if (currentAttributes != null) {
-                                               Attribute attribute = currentAttributes.get(attributeId);
-                                               if (attribute == null) {
-                                                       attribute = new BasicAttribute(attributeId);
-                                                       currentAttributes.put(attribute);
-                                               }
-                                               attribute.add(attributeValue);
-                                       }
-                                       currentEntry = new StringBuilder();
-                               }
-                               currentEntry.append(line);
-                       }
-               } finally {
-                       try {
-                               reader.close();
-                       } catch (IOException e) {
-                               // silent
-                       }
-               }
-               return res;
-       }
-}
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdifWriter.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdifWriter.java
deleted file mode 100644 (file)
index a10f169..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import static org.argeo.util.naming.LdapAttrs.DN;
-import static org.argeo.util.naming.LdapAttrs.member;
-import static org.argeo.util.naming.LdapAttrs.objectClass;
-import static org.argeo.util.naming.LdapAttrs.uniqueMember;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-/** Basic LDIF writer */
-public class LdifWriter {
-       private final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
-       private final Writer writer;
-
-       /** Writer must be closed by caller */
-       public LdifWriter(Writer writer) {
-               this.writer = writer;
-       }
-
-       /** Stream must be closed by caller */
-       public LdifWriter(OutputStream out) {
-               this(new OutputStreamWriter(out, DEFAULT_CHARSET));
-       }
-
-       public void writeEntry(LdapName name, Attributes attributes) throws IOException {
-               try {
-                       // check consistency
-                       Rdn nameRdn = name.getRdn(name.size() - 1);
-                       Attribute nameAttr = attributes.get(nameRdn.getType());
-                       if (!nameAttr.get().equals(nameRdn.getValue()))
-                               throw new IllegalArgumentException(
-                                               "Attribute " + nameAttr.getID() + "=" + nameAttr.get() + " not consistent with DN " + name);
-
-                       writer.append(DN + ": ").append(name.toString()).append('\n');
-                       Attribute objectClassAttr = attributes.get(objectClass.name());
-                       if (objectClassAttr != null)
-                               writeAttribute(objectClassAttr);
-                       attributes: for (NamingEnumeration<? extends Attribute> attrs = attributes.getAll(); attrs.hasMore();) {
-                               Attribute attribute = attrs.next();
-                               if (attribute.getID().equals(DN) || attribute.getID().equals(objectClass.name()))
-                                       continue attributes;// skip DN attribute
-                               if (attribute.getID().equals(member.name()) || attribute.getID().equals(uniqueMember.name()))
-                                       continue attributes;// skip member and uniqueMember attributes, so that they are always written last
-                               writeAttribute(attribute);
-                       }
-                       // write member and uniqueMember attributes last
-                       for (NamingEnumeration<? extends Attribute> attrs = attributes.getAll(); attrs.hasMore();) {
-                               Attribute attribute = attrs.next();
-                               if (attribute.getID().equals(member.name()) || attribute.getID().equals(uniqueMember.name()))
-                                       writeMemberAttribute(attribute);
-                       }
-                       writer.append('\n');
-                       writer.flush();
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot write LDIF", e);
-               }
-       }
-
-       public void write(Map<LdapName, Attributes> entries) throws IOException {
-               for (LdapName dn : entries.keySet())
-                       writeEntry(dn, entries.get(dn));
-       }
-
-       protected void writeAttribute(Attribute attribute) throws NamingException, IOException {
-               for (NamingEnumeration<?> attrValues = attribute.getAll(); attrValues.hasMore();) {
-                       Object value = attrValues.next();
-                       if (value instanceof byte[]) {
-                               String encoded = Base64.getEncoder().encodeToString((byte[]) value);
-                               writer.append(attribute.getID()).append(":: ").append(encoded).append('\n');
-                       } else {
-                               writer.append(attribute.getID()).append(": ").append(value.toString()).append('\n');
-                       }
-               }
-       }
-
-       protected void writeMemberAttribute(Attribute attribute) throws NamingException, IOException {
-               // Note: duplicate entries will be swallowed
-               SortedSet<String> values = new TreeSet<>();
-               for (NamingEnumeration<?> attrValues = attribute.getAll(); attrValues.hasMore();) {
-                       String value = attrValues.next().toString();
-                       values.add(value);
-               }
-
-               for (String value : values) {
-                       writer.append(attribute.getID()).append(": ").append(value).append('\n');
-               }
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/SharedSecret.java b/org.argeo.util/src/org/argeo/util/directory/ldap/SharedSecret.java
deleted file mode 100644 (file)
index eaab167..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.argeo.util.directory.ldap;
-
-import java.time.Instant;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-
-import org.argeo.util.naming.NamingUtils;
-
-public class SharedSecret extends AuthPassword {
-       public final static String X_SHARED_SECRET = "X-SharedSecret";
-       private final Instant expiry;
-
-       public SharedSecret(String authInfo, String authValue) {
-               super(authInfo, authValue);
-               expiry = null;
-       }
-
-       public SharedSecret(AuthPassword authPassword) {
-               super(authPassword);
-               String authInfo = getAuthInfo();
-               if (authInfo.length() == 16) {
-                       expiry = NamingUtils.ldapDateToInstant(authInfo);
-               } else {
-                       expiry = null;
-               }
-       }
-
-       public SharedSecret(ZonedDateTime expiryTimestamp, String value) {
-               super(NamingUtils.instantToLdapDate(expiryTimestamp), value);
-               expiry = expiryTimestamp.withZoneSameInstant(ZoneOffset.UTC).toInstant();
-       }
-
-       public SharedSecret(int hours, String value) {
-               this(ZonedDateTime.now().plusHours(hours), value);
-       }
-
-       @Override
-       protected String getExpectedAuthScheme() {
-               return X_SHARED_SECRET;
-       }
-
-       public boolean isExpired() {
-               if (expiry == null)
-                       return false;
-               return expiry.isBefore(Instant.now());
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/http/HttpHeader.java b/org.argeo.util/src/org/argeo/util/http/HttpHeader.java
deleted file mode 100644 (file)
index 74cf94c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.argeo.util.http;
-
-/** Standard HTTP headers (including WebDav). */
-public enum HttpHeader {
-       AUTHORIZATION("Authorization"), //
-       WWW_AUTHENTICATE("WWW-Authenticate"), //
-       ALLOW("Allow"), //
-
-       // WebDav
-       DAV("DAV"), //
-       DEPTH("Depth"), //
-       ;
-
-       public final static String BASIC = "Basic";
-       public final static String REALM = "realm";
-       public final static String NEGOTIATE = "Negotiate";
-
-       private final String name;
-
-       private HttpHeader(String headerName) {
-               this.name = headerName;
-       }
-
-       public String getHeaderName() {
-               return name;
-       }
-
-       @Override
-       public String toString() {
-               return getHeaderName();
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/http/HttpMethod.java b/org.argeo.util/src/org/argeo/util/http/HttpMethod.java
deleted file mode 100644 (file)
index 27b4d8f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.util.http;
-
-/** Generic HTTP methods. */
-public enum HttpMethod {
-       OPTIONS, //
-       HEAD, //
-       GET, //
-       POST, //
-       PUT, //
-       DELETE, //
-
-       // WebDav
-       PROPFIND, //
-       PROPPATCH, //
-       MKCOL, //
-       MOVE, //
-       COPY, //
-       ;
-}
diff --git a/org.argeo.util/src/org/argeo/util/http/HttpServerUtils.java b/org.argeo.util/src/org/argeo/util/http/HttpServerUtils.java
deleted file mode 100644 (file)
index 9127d2c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.argeo.util.http;
-
-import java.net.URI;
-import java.util.Objects;
-
-import com.sun.net.httpserver.HttpContext;
-import com.sun.net.httpserver.HttpExchange;
-
-public class HttpServerUtils {
-       private final static String SLASH = "/";
-
-       private static String extractPathWithingContext(HttpContext httpContext, String fullPath, boolean startWithSlash) {
-               Objects.requireNonNull(fullPath);
-               String contextPath = httpContext.getPath();
-               if (!fullPath.startsWith(contextPath))
-                       throw new IllegalArgumentException(fullPath + " does not belong to context" + contextPath);
-               String path = fullPath.substring(contextPath.length());
-               // TODO optimise?
-               if (!startWithSlash && path.startsWith(SLASH)) {
-                       path = path.substring(1);
-               } else if (startWithSlash && !path.startsWith(SLASH)) {
-                       path = SLASH + path;
-               }
-               return path;
-       }
-
-       /** Path within the context, NOT starting with a slash. */
-       public static String relativize(HttpExchange exchange) {
-               URI uri = exchange.getRequestURI();
-               HttpContext httpContext = exchange.getHttpContext();
-               return extractPathWithingContext(httpContext, uri.getPath(), false);
-       }
-
-       /** Path within the context, starting with a slash. */
-       public static String subPath(HttpExchange exchange) {
-               URI uri = exchange.getRequestURI();
-               HttpContext httpContext = exchange.getHttpContext();
-               return extractPathWithingContext(httpContext, uri.getPath(), true);
-       }
-
-       /** singleton */
-       private HttpServerUtils() {
-
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/http/HttpStatus.java b/org.argeo.util/src/org/argeo/util/http/HttpStatus.java
deleted file mode 100644 (file)
index 11e0a36..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.argeo.util.http;
-
-/**
- * Standard HTTP response status codes (including WebDav ones).
- * 
- * @see "https://developer.mozilla.org/en-US/docs/Web/HTTP/Status"
- */
-public enum HttpStatus {
-       // Successful responses (200–299)
-       OK(200, "OK"), //
-       NO_CONTENT(204, "No Content"), //
-       MULTI_STATUS(207, "Multi-Status"), // WebDav
-       // Client error responses (400–499)
-       UNAUTHORIZED(401, "Unauthorized"), //
-       FORBIDDEN(403, "Forbidden"), //
-       NOT_FOUND(404, "Not Found"), //
-       // Server error responses (500-599)
-       INTERNAL_SERVER_ERROR(500, "Internal Server Error"), //
-       NOT_IMPLEMENTED(501, "Not Implemented"), //
-       ;
-
-       private final int code;
-       private final String reasonPhrase;
-
-       HttpStatus(int statusCode, String reasonPhrase) {
-               this.code = statusCode;
-               this.reasonPhrase = reasonPhrase;
-       }
-
-       public int getCode() {
-               return code;
-       }
-
-       public String getReasonPhrase() {
-               return reasonPhrase;
-       }
-
-       /**
-        * The status line, as defined by RFC2616.
-        * 
-        * @see "https://www.rfc-editor.org/rfc/rfc2616#section-6.1"
-        */
-       public String getStatusLine(String httpVersion) {
-               return httpVersion + " " + code + " " + reasonPhrase;
-       }
-
-       public static HttpStatus parseStatusLine(String statusLine) {
-               try {
-                       String[] arr = statusLine.split(" ");
-                       int code = Integer.parseInt(arr[1]);
-                       for (HttpStatus status : values()) {
-                               if (status.getCode() == code)
-                                       return status;
-                       }
-               } catch (Exception e) {
-                       throw new IllegalArgumentException("Invalid status line: " + statusLine, e);
-               }
-               throw new IllegalArgumentException("Unkown status code: " + statusLine);
-       }
-
-       @Override
-       public String toString() {
-               return code + " " + reasonPhrase;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/internal/DisplayQName.java b/org.argeo.util/src/org/argeo/util/internal/DisplayQName.java
deleted file mode 100644 (file)
index 6cc39dc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.argeo.util.internal;
-
-import javax.xml.namespace.QName;
-
-public class DisplayQName extends QName {
-               private static final long serialVersionUID = 2376484886212253123L;
-
-               public DisplayQName(String namespaceURI, String localPart, String prefix) {
-                       super(namespaceURI, localPart, prefix);
-               }
-
-               public DisplayQName(String localPart) {
-                       super(localPart);
-               }
-
-               @Override
-               public String toString() {
-                       String prefix = getPrefix();
-                       assert prefix != null;
-                       return "".equals(prefix) ? getLocalPart() : prefix + ":" + getLocalPart();
-               }
-
-       }
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/util/naming/Distinguished.java b/org.argeo.util/src/org/argeo/util/naming/Distinguished.java
deleted file mode 100644 (file)
index e339ede..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.util.naming;
-
-import java.util.EnumSet;
-import java.util.Set;
-import java.util.TreeSet;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-
-/**
- * An object that can be identified with an X.500 distinguished name.
- * 
- * @see "https://tools.ietf.org/html/rfc1779"
- */
-public interface Distinguished {
-       /** The related distinguished name. */
-       String dn();
-
-       /** The related distinguished name as an {@link LdapName}. */
-       default LdapName distinguishedName() {
-               try {
-                       return new LdapName(dn());
-               } catch (InvalidNameException e) {
-                       throw new IllegalArgumentException("Distinguished name " + dn() + " is not properly formatted.", e);
-               }
-       }
-
-       /** List all DNs of an enumeration as strings. */
-       static Set<String> enumToDns(EnumSet<? extends Distinguished> enumSet) {
-               Set<String> res = new TreeSet<>();
-               for (Enum<? extends Distinguished> enm : enumSet) {
-                       res.add(((Distinguished) enm).dn());
-               }
-               return res;
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/naming/LdapAttrs.csv b/org.argeo.util/src/org/argeo/util/naming/LdapAttrs.csv
deleted file mode 100644 (file)
index 676d727..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-uid,,,0.9.2342.19200300.100.1.1,,RFC 4519
-mail,,,0.9.2342.19200300.100.1.3,,RFC 4524
-info,,,0.9.2342.19200300.100.1.4,,RFC 4524
-drink,,,0.9.2342.19200300.100.1.5,,RFC 4524
-roomNumber,,,0.9.2342.19200300.100.1.6,,RFC 4524
-photo,,,0.9.2342.19200300.100.1.7,,RFC 2798
-userClass,,,0.9.2342.19200300.100.1.8,,RFC 4524
-host,,,0.9.2342.19200300.100.1.9,,RFC 4524
-manager,,,0.9.2342.19200300.100.1.10,,RFC 4524
-documentIdentifier,,,0.9.2342.19200300.100.1.11,,RFC 4524
-documentTitle,,,0.9.2342.19200300.100.1.12,,RFC 4524
-documentVersion,,,0.9.2342.19200300.100.1.13,,RFC 4524
-documentAuthor,,,0.9.2342.19200300.100.1.14,,RFC 4524
-documentLocation,,,0.9.2342.19200300.100.1.15,,RFC 4524
-homePhone,,,0.9.2342.19200300.100.1.20,,RFC 4524
-secretary,,,0.9.2342.19200300.100.1.21,,RFC 4524
-dc,,,0.9.2342.19200300.100.1.25,,RFC 4519
-associatedDomain,,,0.9.2342.19200300.100.1.37,,RFC 4524
-associatedName,,,0.9.2342.19200300.100.1.38,,RFC 4524
-homePostalAddress,,,0.9.2342.19200300.100.1.39,,RFC 4524
-personalTitle,,,0.9.2342.19200300.100.1.40,,RFC 4524
-mobile,,,0.9.2342.19200300.100.1.41,,RFC 4524
-pager,,,0.9.2342.19200300.100.1.42,,RFC 4524
-co,,,0.9.2342.19200300.100.1.43,,RFC 4524
-uniqueIdentifier,,,0.9.2342.19200300.100.1.44,,RFC 4524
-organizationalStatus,,,0.9.2342.19200300.100.1.45,,RFC 4524
-buildingName,,,0.9.2342.19200300.100.1.48,,RFC 4524
-audio,,,0.9.2342.19200300.100.1.55,,RFC 2798
-documentPublisher,,,0.9.2342.19200300.100.1.56,,RFC 4524
-jpegPhoto,,,0.9.2342.19200300.100.1.60,,RFC 2798
-vendorName,,,1.3.6.1.1.4,,RFC 3045
-vendorVersion,,,1.3.6.1.1.5,,RFC 3045
-entryUUID,,,1.3.6.1.1.16.4,,RFC 4530
-entryDN,,,1.3.6.1.1.20,,RFC 5020
-labeledURI,,,1.3.6.1.4.1.250.1.57,,RFC 2798
-numSubordinates,,,1.3.6.1.4.1.453.16.2.103,,draft-ietf-boreham-numsubordinates
-namingContexts,,,1.3.6.1.4.1.1466.101.120.5,,RFC 4512
-altServer,,,1.3.6.1.4.1.1466.101.120.6,,RFC 4512
-supportedExtension,,,1.3.6.1.4.1.1466.101.120.7,,RFC 4512
-supportedControl,,,1.3.6.1.4.1.1466.101.120.13,,RFC 4512
-supportedSASLMechanisms,,,1.3.6.1.4.1.1466.101.120.14,,RFC 4512
-supportedLDAPVersion,,,1.3.6.1.4.1.1466.101.120.15,,RFC 4512
-ldapSyntaxes,,,1.3.6.1.4.1.1466.101.120.16,,RFC 4512
-supportedAuthPasswordSchemes,,,1.3.6.1.4.1.4203.1.3.3,,RFC 3112
-authPassword,,,1.3.6.1.4.1.4203.1.3.4,,RFC 3112
-supportedFeatures,,,1.3.6.1.4.1.4203.1.3.5,,RFC 4512
-inheritable,,,1.3.6.1.4.1.7628.5.4.1,,draft-ietf-ldup-subentry
-blockInheritance,,,1.3.6.1.4.1.7628.5.4.2,,draft-ietf-ldup-subentry
-objectClass,,,2.5.4.0,,RFC 4512
-aliasedObjectName,,,2.5.4.1,,RFC 4512
-cn,,,2.5.4.3,,RFC 4519
-sn,,,2.5.4.4,,RFC 4519
-serialNumber,,,2.5.4.5,,RFC 4519
-c,,,2.5.4.6,,RFC 4519
-l,,,2.5.4.7,,RFC 4519
-st,,,2.5.4.8,,RFC 4519
-street,,,2.5.4.9,,RFC 4519
-o,,,2.5.4.10,,RFC 4519
-ou,,,2.5.4.11,,RFC 4519
-title,,,2.5.4.12,,RFC 4519
-description,,,2.5.4.13,,RFC 4519
-searchGuide,,,2.5.4.14,,RFC 4519
-businessCategory,,,2.5.4.15,,RFC 4519
-postalAddress,,,2.5.4.16,,RFC 4519
-postalCode,,,2.5.4.17,,RFC 4519
-postOfficeBox,,,2.5.4.18,,RFC 4519
-physicalDeliveryOfficeName,,,2.5.4.19,,RFC 4519
-telephoneNumber,,,2.5.4.20,,RFC 4519
-telexNumber,,,2.5.4.21,,RFC 4519
-teletexTerminalIdentifier,,,2.5.4.22,,RFC 4519
-facsimileTelephoneNumber,,,2.5.4.23,,RFC 4519
-x121Address,,,2.5.4.24,,RFC 4519
-internationalISDNNumber,,,2.5.4.25,,RFC 4519
-registeredAddress,,,2.5.4.26,,RFC 4519
-destinationIndicator,,,2.5.4.27,,RFC 4519
-preferredDeliveryMethod,,,2.5.4.28,,RFC 4519
-member,,,2.5.4.31,,RFC 4519
-owner,,,2.5.4.32,,RFC 4519
-roleOccupant,,,2.5.4.33,,RFC 4519
-seeAlso,,,2.5.4.34,,RFC 4519
-userPassword,,,2.5.4.35,,RFC 4519
-userCertificate,,,2.5.4.36,,RFC 4523
-cACertificate,,,2.5.4.37,,RFC 4523
-authorityRevocationList,,,2.5.4.38,,RFC 4523
-certificateRevocationList,,,2.5.4.39,,RFC 4523
-crossCertificatePair,,,2.5.4.40,,RFC 4523
-name,,,2.5.4.41,,RFC 4519
-givenName,,,2.5.4.42,,RFC 4519
-initials,,,2.5.4.43,,RFC 4519
-generationQualifier,,,2.5.4.44,,RFC 4519
-x500UniqueIdentifier,,,2.5.4.45,,RFC 4519
-dnQualifier,,,2.5.4.46,,RFC 4519
-enhancedSearchGuide,,,2.5.4.47,,RFC 4519
-distinguishedName,,,2.5.4.49,,RFC 4519
-uniqueMember,,,2.5.4.50,,RFC 4519
-houseIdentifier,,,2.5.4.51,,RFC 4519
-supportedAlgorithms,,,2.5.4.52,,RFC 4523
-deltaRevocationList,,,2.5.4.53,,RFC 4523
-createTimestamp,,,2.5.18.1,,RFC 4512
-modifyTimestamp,,,2.5.18.2,,RFC 4512
-creatorsName,,,2.5.18.3,,RFC 4512
-modifiersName,,,2.5.18.4,,RFC 4512
-subschemaSubentry,,,2.5.18.10,,RFC 4512
-dITStructureRules,,,2.5.21.1,,RFC 4512
-dITContentRules,,,2.5.21.2,,RFC 4512
-matchingRules,,,2.5.21.4,,RFC 4512
-attributeTypes,,,2.5.21.5,,RFC 4512
-objectClasses,,,2.5.21.6,,RFC 4512
-nameForms,,,2.5.21.7,,RFC 4512
-matchingRuleUse,,,2.5.21.8,,RFC 4512
-structuralObjectClass,,,2.5.21.9,,RFC 4512
-governingStructureRule,,,2.5.21.10,,RFC 4512
-carLicense,,,2.16.840.1.113730.3.1.1,,RFC 2798
-departmentNumber,,,2.16.840.1.113730.3.1.2,,RFC 2798
-employeeNumber,,,2.16.840.1.113730.3.1.3,,RFC 2798
-employeeType,,,2.16.840.1.113730.3.1.4,,RFC 2798
-changeNumber,,,2.16.840.1.113730.3.1.5,,draft-good-ldap-changelog
-targetDN,,,2.16.840.1.113730.3.1.6,,draft-good-ldap-changelog
-changeType,,,2.16.840.1.113730.3.1.7,,draft-good-ldap-changelog
-changes,,,2.16.840.1.113730.3.1.8,,draft-good-ldap-changelog
-newRDN,,,2.16.840.1.113730.3.1.9,,draft-good-ldap-changelog
-deleteOldRDN,,,2.16.840.1.113730.3.1.10,,draft-good-ldap-changelog
-newSuperior,,,2.16.840.1.113730.3.1.11,,draft-good-ldap-changelog
-ref,,,2.16.840.1.113730.3.1.34,,RFC 3296
-changelog,,,2.16.840.1.113730.3.1.35,,draft-good-ldap-changelog
-preferredLanguage,,,2.16.840.1.113730.3.1.39,,RFC 2798
-userSMIMECertificate,,,2.16.840.1.113730.3.1.40,,RFC 2798
-userPKCS12,,,2.16.840.1.113730.3.1.216,,RFC 2798
-displayName,,,2.16.840.1.113730.3.1.241,,RFC 2798
diff --git a/org.argeo.util/src/org/argeo/util/naming/LdapAttrs.java b/org.argeo.util/src/org/argeo/util/naming/LdapAttrs.java
deleted file mode 100644 (file)
index 1a6642f..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-package org.argeo.util.naming;
-
-import java.util.function.Supplier;
-
-import javax.xml.namespace.QName;
-
-import org.argeo.util.internal.DisplayQName;
-
-/**
- * Standard LDAP attributes as per:<br>
- * - <a href= "https://www.ldap.com/ldap-oid-reference">Standard LDAP</a><br>
- * - <a href=
- * "https://github.com/krb5/krb5/blob/master/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema">Kerberos
- * LDAP (partial)</a>
- */
-public enum LdapAttrs implements SpecifiedName, Supplier<String> {
-       /** */
-       uid("0.9.2342.19200300.100.1.1", "RFC 4519"),
-       /** */
-       mail("0.9.2342.19200300.100.1.3", "RFC 4524"),
-       /** */
-       info("0.9.2342.19200300.100.1.4", "RFC 4524"),
-       /** */
-       drink("0.9.2342.19200300.100.1.5", "RFC 4524"),
-       /** */
-       roomNumber("0.9.2342.19200300.100.1.6", "RFC 4524"),
-       /** */
-       photo("0.9.2342.19200300.100.1.7", "RFC 2798"),
-       /** */
-       userClass("0.9.2342.19200300.100.1.8", "RFC 4524"),
-       /** */
-       host("0.9.2342.19200300.100.1.9", "RFC 4524"),
-       /** */
-       manager("0.9.2342.19200300.100.1.10", "RFC 4524"),
-       /** */
-       documentIdentifier("0.9.2342.19200300.100.1.11", "RFC 4524"),
-       /** */
-       documentTitle("0.9.2342.19200300.100.1.12", "RFC 4524"),
-       /** */
-       documentVersion("0.9.2342.19200300.100.1.13", "RFC 4524"),
-       /** */
-       documentAuthor("0.9.2342.19200300.100.1.14", "RFC 4524"),
-       /** */
-       documentLocation("0.9.2342.19200300.100.1.15", "RFC 4524"),
-       /** */
-       homePhone("0.9.2342.19200300.100.1.20", "RFC 4524"),
-       /** */
-       secretary("0.9.2342.19200300.100.1.21", "RFC 4524"),
-       /** */
-       dc("0.9.2342.19200300.100.1.25", "RFC 4519"),
-       /** */
-       associatedDomain("0.9.2342.19200300.100.1.37", "RFC 4524"),
-       /** */
-       associatedName("0.9.2342.19200300.100.1.38", "RFC 4524"),
-       /** */
-       homePostalAddress("0.9.2342.19200300.100.1.39", "RFC 4524"),
-       /** */
-       personalTitle("0.9.2342.19200300.100.1.40", "RFC 4524"),
-       /** */
-       mobile("0.9.2342.19200300.100.1.41", "RFC 4524"),
-       /** */
-       pager("0.9.2342.19200300.100.1.42", "RFC 4524"),
-       /** */
-       co("0.9.2342.19200300.100.1.43", "RFC 4524"),
-       /** */
-       uniqueIdentifier("0.9.2342.19200300.100.1.44", "RFC 4524"),
-       /** */
-       organizationalStatus("0.9.2342.19200300.100.1.45", "RFC 4524"),
-       /** */
-       buildingName("0.9.2342.19200300.100.1.48", "RFC 4524"),
-       /** */
-       audio("0.9.2342.19200300.100.1.55", "RFC 2798"),
-       /** */
-       documentPublisher("0.9.2342.19200300.100.1.56", "RFC 4524"),
-       /** */
-       jpegPhoto("0.9.2342.19200300.100.1.60", "RFC 2798"),
-       /** */
-       vendorName("1.3.6.1.1.4", "RFC 3045"),
-       /** */
-       vendorVersion("1.3.6.1.1.5", "RFC 3045"),
-       /** */
-       entryUUID("1.3.6.1.1.16.4", "RFC 4530"),
-       /** */
-       entryDN("1.3.6.1.1.20", "RFC 5020"),
-       /** */
-       labeledURI("1.3.6.1.4.1.250.1.57", "RFC 2798"),
-       /** */
-       numSubordinates("1.3.6.1.4.1.453.16.2.103", "draft-ietf-boreham-numsubordinates"),
-       /** */
-       namingContexts("1.3.6.1.4.1.1466.101.120.5", "RFC 4512"),
-       /** */
-       altServer("1.3.6.1.4.1.1466.101.120.6", "RFC 4512"),
-       /** */
-       supportedExtension("1.3.6.1.4.1.1466.101.120.7", "RFC 4512"),
-       /** */
-       supportedControl("1.3.6.1.4.1.1466.101.120.13", "RFC 4512"),
-       /** */
-       supportedSASLMechanisms("1.3.6.1.4.1.1466.101.120.14", "RFC 4512"),
-       /** */
-       supportedLDAPVersion("1.3.6.1.4.1.1466.101.120.15", "RFC 4512"),
-       /** */
-       ldapSyntaxes("1.3.6.1.4.1.1466.101.120.16", "RFC 4512"),
-       /** */
-       supportedAuthPasswordSchemes("1.3.6.1.4.1.4203.1.3.3", "RFC 3112"),
-       /** */
-       authPassword("1.3.6.1.4.1.4203.1.3.4", "RFC 3112"),
-       /** */
-       supportedFeatures("1.3.6.1.4.1.4203.1.3.5", "RFC 4512"),
-       /** */
-       inheritable("1.3.6.1.4.1.7628.5.4.1", "draft-ietf-ldup-subentry"),
-       /** */
-       blockInheritance("1.3.6.1.4.1.7628.5.4.2", "draft-ietf-ldup-subentry"),
-       /** */
-       objectClass("2.5.4.0", "RFC 4512"),
-       /** */
-       aliasedObjectName("2.5.4.1", "RFC 4512"),
-       /** */
-       cn("2.5.4.3", "RFC 4519"),
-       /** */
-       sn("2.5.4.4", "RFC 4519"),
-       /** */
-       serialNumber("2.5.4.5", "RFC 4519"),
-       /** */
-       c("2.5.4.6", "RFC 4519"),
-       /** */
-       l("2.5.4.7", "RFC 4519"),
-       /** */
-       st("2.5.4.8", "RFC 4519"),
-       /** */
-       street("2.5.4.9", "RFC 4519"),
-       /** */
-       o("2.5.4.10", "RFC 4519"),
-       /** */
-       ou("2.5.4.11", "RFC 4519"),
-       /** */
-       title("2.5.4.12", "RFC 4519"),
-       /** */
-       description("2.5.4.13", "RFC 4519"),
-       /** */
-       searchGuide("2.5.4.14", "RFC 4519"),
-       /** */
-       businessCategory("2.5.4.15", "RFC 4519"),
-       /** */
-       postalAddress("2.5.4.16", "RFC 4519"),
-       /** */
-       postalCode("2.5.4.17", "RFC 4519"),
-       /** */
-       postOfficeBox("2.5.4.18", "RFC 4519"),
-       /** */
-       physicalDeliveryOfficeName("2.5.4.19", "RFC 4519"),
-       /** */
-       telephoneNumber("2.5.4.20", "RFC 4519"),
-       /** */
-       telexNumber("2.5.4.21", "RFC 4519"),
-       /** */
-       teletexTerminalIdentifier("2.5.4.22", "RFC 4519"),
-       /** */
-       facsimileTelephoneNumber("2.5.4.23", "RFC 4519"),
-       /** */
-       x121Address("2.5.4.24", "RFC 4519"),
-       /** */
-       internationalISDNNumber("2.5.4.25", "RFC 4519"),
-       /** */
-       registeredAddress("2.5.4.26", "RFC 4519"),
-       /** */
-       destinationIndicator("2.5.4.27", "RFC 4519"),
-       /** */
-       preferredDeliveryMethod("2.5.4.28", "RFC 4519"),
-       /** */
-       member("2.5.4.31", "RFC 4519"),
-       /** */
-       owner("2.5.4.32", "RFC 4519"),
-       /** */
-       roleOccupant("2.5.4.33", "RFC 4519"),
-       /** */
-       seeAlso("2.5.4.34", "RFC 4519"),
-       /** */
-       userPassword("2.5.4.35", "RFC 4519"),
-       /** */
-       userCertificate("2.5.4.36", "RFC 4523"),
-       /** */
-       cACertificate("2.5.4.37", "RFC 4523"),
-       /** */
-       authorityRevocationList("2.5.4.38", "RFC 4523"),
-       /** */
-       certificateRevocationList("2.5.4.39", "RFC 4523"),
-       /** */
-       crossCertificatePair("2.5.4.40", "RFC 4523"),
-       /** */
-       name("2.5.4.41", "RFC 4519"),
-       /** */
-       givenName("2.5.4.42", "RFC 4519"),
-       /** */
-       initials("2.5.4.43", "RFC 4519"),
-       /** */
-       generationQualifier("2.5.4.44", "RFC 4519"),
-       /** */
-       x500UniqueIdentifier("2.5.4.45", "RFC 4519"),
-       /** */
-       dnQualifier("2.5.4.46", "RFC 4519"),
-       /** */
-       enhancedSearchGuide("2.5.4.47", "RFC 4519"),
-       /** */
-       distinguishedName("2.5.4.49", "RFC 4519"),
-       /** */
-       uniqueMember("2.5.4.50", "RFC 4519"),
-       /** */
-       houseIdentifier("2.5.4.51", "RFC 4519"),
-       /** */
-       supportedAlgorithms("2.5.4.52", "RFC 4523"),
-       /** */
-       deltaRevocationList("2.5.4.53", "RFC 4523"),
-       /** */
-       createTimestamp("2.5.18.1", "RFC 4512"),
-       /** */
-       modifyTimestamp("2.5.18.2", "RFC 4512"),
-       /** */
-       creatorsName("2.5.18.3", "RFC 4512"),
-       /** */
-       modifiersName("2.5.18.4", "RFC 4512"),
-       /** */
-       subschemaSubentry("2.5.18.10", "RFC 4512"),
-       /** */
-       dITStructureRules("2.5.21.1", "RFC 4512"),
-       /** */
-       dITContentRules("2.5.21.2", "RFC 4512"),
-       /** */
-       matchingRules("2.5.21.4", "RFC 4512"),
-       /** */
-       attributeTypes("2.5.21.5", "RFC 4512"),
-       /** */
-       objectClasses("2.5.21.6", "RFC 4512"),
-       /** */
-       nameForms("2.5.21.7", "RFC 4512"),
-       /** */
-       matchingRuleUse("2.5.21.8", "RFC 4512"),
-       /** */
-       structuralObjectClass("2.5.21.9", "RFC 4512"),
-       /** */
-       governingStructureRule("2.5.21.10", "RFC 4512"),
-       /** */
-       carLicense("2.16.840.1.113730.3.1.1", "RFC 2798"),
-       /** */
-       departmentNumber("2.16.840.1.113730.3.1.2", "RFC 2798"),
-       /** */
-       employeeNumber("2.16.840.1.113730.3.1.3", "RFC 2798"),
-       /** */
-       employeeType("2.16.840.1.113730.3.1.4", "RFC 2798"),
-       /** */
-       changeNumber("2.16.840.1.113730.3.1.5", "draft-good-ldap-changelog"),
-       /** */
-       targetDN("2.16.840.1.113730.3.1.6", "draft-good-ldap-changelog"),
-       /** */
-       changeType("2.16.840.1.113730.3.1.7", "draft-good-ldap-changelog"),
-       /** */
-       changes("2.16.840.1.113730.3.1.8", "draft-good-ldap-changelog"),
-       /** */
-       newRDN("2.16.840.1.113730.3.1.9", "draft-good-ldap-changelog"),
-       /** */
-       deleteOldRDN("2.16.840.1.113730.3.1.10", "draft-good-ldap-changelog"),
-       /** */
-       newSuperior("2.16.840.1.113730.3.1.11", "draft-good-ldap-changelog"),
-       /** */
-       ref("2.16.840.1.113730.3.1.34", "RFC 3296"),
-       /** */
-       changelog("2.16.840.1.113730.3.1.35", "draft-good-ldap-changelog"),
-       /** */
-       preferredLanguage("2.16.840.1.113730.3.1.39", "RFC 2798"),
-       /** */
-       userSMIMECertificate("2.16.840.1.113730.3.1.40", "RFC 2798"),
-       /** */
-       userPKCS12("2.16.840.1.113730.3.1.216", "RFC 2798"),
-       /** */
-       displayName("2.16.840.1.113730.3.1.241", "RFC 2798"),
-
-       // Sun memberOf
-       memberOf("1.2.840.113556.1.2.102", "389 DS memberOf"),
-
-       // KERBEROS (partial)
-       krbPrincipalName("2.16.840.1.113719.1.301.6.8.1", "Novell Kerberos Schema Definitions"),
-
-       // RFC 2985 and RFC 3039 (partial)
-       dateOfBirth("1.3.6.1.5.5.7.9.1", "RFC 2985"),
-       /** */
-       placeOfBirth("1.3.6.1.5.5.7.9.2", "RFC 2985"),
-       /** */
-       gender("1.3.6.1.5.5.7.9.3", "RFC 2985"),
-       /** */
-       countryOfCitizenship("1.3.6.1.5.5.7.9.4", "RFC 2985"),
-       /** */
-       countryOfResidence("1.3.6.1.5.5.7.9.5", "RFC 2985"),
-
-       // RFC 2307bis (partial)
-       /** */
-       uidNumber("1.3.6.1.1.1.1.0", "RFC 2307bis"),
-       /** */
-       gidNumber("1.3.6.1.1.1.1.1", "RFC 2307bis"),
-       /** */
-       homeDirectory("1.3.6.1.1.1.1.3", "RFC 2307bis"),
-       /** */
-       loginShell("1.3.6.1.1.1.1.4", "RFC 2307bis"),
-       /** */
-       memberUid("1.3.6.1.1.1.1.12", "RFC 2307bis"),
-
-       //
-       ;
-
-       public final static String DN = "dn";
-
-//     private final static String LDAP_ = "ldap:";
-
-       private final String oid, spec;
-       private final QName value;
-
-       LdapAttrs(String oid, String spec) {
-               this.oid = oid;
-               this.spec = spec;
-               this.value = new DisplayQName(LdapObjs.LDAP_NAMESPACE_URI, name(), LdapObjs.LDAP_DEFAULT_PREFIX);
-       }
-
-       public QName qName() {
-               return value;
-       }
-
-       @Override
-       public String getID() {
-               return oid;
-       }
-
-       @Override
-       public String getSpec() {
-               return spec;
-       }
-
-       @Deprecated
-       public String property() {
-               return get();
-       }
-
-       @Deprecated
-       public String qualified() {
-               return get();
-       }
-
-       @Override
-       public String get() {
-               return LdapObjs.LDAP_DEFAULT_PREFIX + ":" + name();
-       }
-
-       @Override
-       public final String toString() {
-               // must return the name
-               return name();
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/naming/LdapObjs.csv b/org.argeo.util/src/org/argeo/util/naming/LdapObjs.csv
deleted file mode 100644 (file)
index 3d907cb..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-account,,,0.9.2342.19200300.100.4.5,,RFC 4524
-document,,,0.9.2342.19200300.100.4.6,,RFC 4524
-room,,,0.9.2342.19200300.100.4.7,,RFC 4524
-documentSeries,,,0.9.2342.19200300.100.4.9,,RFC 4524
-domain,,,0.9.2342.19200300.100.4.13,,RFC 4524
-rFC822localPart,,,0.9.2342.19200300.100.4.14,,RFC 4524
-domainRelatedObject,,,0.9.2342.19200300.100.4.17,,RFC 4524
-friendlyCountry,,,0.9.2342.19200300.100.4.18,,RFC 4524
-simpleSecurityObject,,,0.9.2342.19200300.100.4.19,,RFC 4524
-uidObject,,,1.3.6.1.1.3.1,,RFC 4519
-extensibleObject,,,1.3.6.1.4.1.1466.101.120.111,,RFC 4512
-dcObject,,,1.3.6.1.4.1.1466.344,,RFC 4519
-authPasswordObject,,,1.3.6.1.4.1.4203.1.4.7,,RFC 3112
-namedObject,,,1.3.6.1.4.1.5322.13.1.1,,draft-howard-namedobject
-inheritableLDAPSubEntry,,,1.3.6.1.4.1.7628.5.6.1.1,,draft-ietf-ldup-subentry
-top,,,2.5.6.0,,RFC 4512
-alias,,,2.5.6.1,,RFC 4512
-country,,,2.5.6.2,,RFC 4519
-locality,,,2.5.6.3,,RFC 4519
-organization,,,2.5.6.4,,RFC 4519
-organizationalUnit,,,2.5.6.5,,RFC 4519
-person,,,2.5.6.6,,RFC 4519
-organizationalPerson,,,2.5.6.7,,RFC 4519
-organizationalRole,,,2.5.6.8,,RFC 4519
-groupOfNames,,,2.5.6.9,,RFC 4519
-residentialPerson,,,2.5.6.10,,RFC 4519
-applicationProcess,,,2.5.6.11,,RFC 4519
-device,,,2.5.6.14,,RFC 4519
-strongAuthenticationUser,,,2.5.6.15,,RFC 4523
-certificationAuthority,,,2.5.6.16,,RFC 4523
-certificationAuthority-V2,,,2.5.6.16.2,,RFC 4523
-groupOfUniqueNames,,,2.5.6.17,,RFC 4519
-userSecurityInformation,,,2.5.6.18,,RFC 4523
-cRLDistributionPoint,,,2.5.6.19,,RFC 4523
-pkiUser,,,2.5.6.21,,RFC 4523
-pkiCA,,,2.5.6.22,,RFC 4523
-deltaCRL,,,2.5.6.23,,RFC 4523
-subschema,,,2.5.20.1,,RFC 4512
-ldapSubEntry,,,2.16.840.1.113719.2.142.6.1.1,,draft-ietf-ldup-subentry
-changeLogEntry,,,2.16.840.1.113730.3.2.1,,draft-good-ldap-changelog
-inetOrgPerson,,,2.16.840.1.113730.3.2.2,,RFC 2798
-referral,,,2.16.840.1.113730.3.2.6,,RFC 3296
diff --git a/org.argeo.util/src/org/argeo/util/naming/LdapObjs.java b/org.argeo.util/src/org/argeo/util/naming/LdapObjs.java
deleted file mode 100644 (file)
index 995c68c..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-package org.argeo.util.naming;
-
-import java.util.function.Supplier;
-
-import javax.xml.namespace.QName;
-
-import org.argeo.util.internal.DisplayQName;
-
-/**
- * Standard LDAP object classes as per
- * <a href="https://www.ldap.com/ldap-oid-reference">https://www.ldap.com/ldap-
- * oid-reference</a>
- */
-public enum LdapObjs implements SpecifiedName, Supplier<String> {
-       account("0.9.2342.19200300.100.4.5", "RFC 4524"),
-       /** */
-       document("0.9.2342.19200300.100.4.6", "RFC 4524"),
-       /** */
-       room("0.9.2342.19200300.100.4.7", "RFC 4524"),
-       /** */
-       documentSeries("0.9.2342.19200300.100.4.9", "RFC 4524"),
-       /** */
-       domain("0.9.2342.19200300.100.4.13", "RFC 4524"),
-       /** */
-       rFC822localPart("0.9.2342.19200300.100.4.14", "RFC 4524"),
-       /** */
-       domainRelatedObject("0.9.2342.19200300.100.4.17", "RFC 4524"),
-       /** */
-       friendlyCountry("0.9.2342.19200300.100.4.18", "RFC 4524"),
-       /** */
-       simpleSecurityObject("0.9.2342.19200300.100.4.19", "RFC 4524"),
-       /** */
-       uidObject("1.3.6.1.1.3.1", "RFC 4519"),
-       /** */
-       extensibleObject("1.3.6.1.4.1.1466.101.120.111", "RFC 4512"),
-       /** */
-       dcObject("1.3.6.1.4.1.1466.344", "RFC 4519"),
-       /** */
-       authPasswordObject("1.3.6.1.4.1.4203.1.4.7", "RFC 3112"),
-       /** */
-       namedObject("1.3.6.1.4.1.5322.13.1.1", "draft-howard-namedobject"),
-       /** */
-       inheritableLDAPSubEntry("1.3.6.1.4.1.7628.5.6.1.1", "draft-ietf-ldup-subentry"),
-       /** */
-       top("2.5.6.0", "RFC 4512"),
-       /** */
-       alias("2.5.6.1", "RFC 4512"),
-       /** */
-       country("2.5.6.2", "RFC 4519"),
-       /** */
-       locality("2.5.6.3", "RFC 4519"),
-       /** */
-       organization("2.5.6.4", "RFC 4519"),
-       /** */
-       organizationalUnit("2.5.6.5", "RFC 4519"),
-       /** */
-       person("2.5.6.6", "RFC 4519"),
-       /** */
-       organizationalPerson("2.5.6.7", "RFC 4519"),
-       /** */
-       organizationalRole("2.5.6.8", "RFC 4519"),
-       /** */
-       groupOfNames("2.5.6.9", "RFC 4519"),
-       /** */
-       residentialPerson("2.5.6.10", "RFC 4519"),
-       /** */
-       applicationProcess("2.5.6.11", "RFC 4519"),
-       /** */
-       device("2.5.6.14", "RFC 4519"),
-       /** */
-       strongAuthenticationUser("2.5.6.15", "RFC 4523"),
-       /** */
-       certificationAuthority("2.5.6.16", "RFC 4523"),
-       // /** Should be certificationAuthority-V2 */
-       // certificationAuthority_V2("2.5.6.16.2", "RFC 4523") {
-       // },
-       /** */
-       groupOfUniqueNames("2.5.6.17", "RFC 4519"),
-       /** */
-       userSecurityInformation("2.5.6.18", "RFC 4523"),
-       /** */
-       cRLDistributionPoint("2.5.6.19", "RFC 4523"),
-       /** */
-       pkiUser("2.5.6.21", "RFC 4523"),
-       /** */
-       pkiCA("2.5.6.22", "RFC 4523"),
-       /** */
-       deltaCRL("2.5.6.23", "RFC 4523"),
-       /** */
-       subschema("2.5.20.1", "RFC 4512"),
-       /** */
-       ldapSubEntry("2.16.840.1.113719.2.142.6.1.1", "draft-ietf-ldup-subentry"),
-       /** */
-       changeLogEntry("2.16.840.1.113730.3.2.1", "draft-good-ldap-changelog"),
-       /** */
-       inetOrgPerson("2.16.840.1.113730.3.2.2", "RFC 2798"),
-       /** */
-       referral("2.16.840.1.113730.3.2.6", "RFC 3296"),
-
-       // RFC 2307bis (partial)
-       /** */
-       posixAccount("1.3.6.1.1.1.2.0", "RFC 2307bis"),
-       /** */
-       posixGroup("1.3.6.1.1.1.2.2", "RFC 2307bis"),
-
-       //
-       ;
-
-       /** MUST be equal to ContentRepository LDAP namespace. */
-       final static String LDAP_NAMESPACE_URI = "http://www.argeo.org/ns/ldap";
-       /** MUST be equal to ContentRepository LDAP prefix. */
-       final static String LDAP_DEFAULT_PREFIX = "ldap";
-
-       private final String oid, spec;
-       private final QName value;
-
-       private LdapObjs(String oid, String spec) {
-               this.oid = oid;
-               this.spec = spec;
-               this.value = new DisplayQName(LDAP_NAMESPACE_URI, name(), LDAP_DEFAULT_PREFIX);
-       }
-
-       public QName qName() {
-               return value;
-       }
-
-       public String getOid() {
-               return oid;
-       }
-
-       public String getSpec() {
-               return spec;
-       }
-
-       @Deprecated
-       public String property() {
-               return get();
-       }
-
-       @Override
-       public String get() {
-               return LdapObjs.LDAP_DEFAULT_PREFIX + ":" + name();
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/naming/NamingUtils.java b/org.argeo.util/src/org/argeo/util/naming/NamingUtils.java
deleted file mode 100644 (file)
index ff4ed31..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-package org.argeo.util.naming;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeParseException;
-import java.time.temporal.ChronoField;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public class NamingUtils {
-       /** As per https://tools.ietf.org/html/rfc4517#section-3.3.13 */
-       private final static DateTimeFormatter utcLdapDate = DateTimeFormatter.ofPattern("uuuuMMddHHmmssX")
-                       .withZone(ZoneOffset.UTC);
-
-       /** @return null if not parseable */
-       public static Instant ldapDateToInstant(String ldapDate) {
-               try {
-                       return OffsetDateTime.parse(ldapDate, utcLdapDate).toInstant();
-               } catch (DateTimeParseException e) {
-                       return null;
-               }
-       }
-
-       /** @return null if not parseable */
-       public static ZonedDateTime ldapDateToZonedDateTime(String ldapDate) {
-               try {
-                       return OffsetDateTime.parse(ldapDate, utcLdapDate).toZonedDateTime();
-               } catch (DateTimeParseException e) {
-                       return null;
-               }
-       }
-
-       public static Calendar ldapDateToCalendar(String ldapDate) {
-               OffsetDateTime instant = OffsetDateTime.parse(ldapDate, utcLdapDate);
-               GregorianCalendar calendar = new GregorianCalendar();
-               calendar.set(Calendar.DAY_OF_MONTH, instant.get(ChronoField.DAY_OF_MONTH));
-               calendar.set(Calendar.MONTH, instant.get(ChronoField.MONTH_OF_YEAR));
-               calendar.set(Calendar.YEAR, instant.get(ChronoField.YEAR));
-               return calendar;
-       }
-
-       public static String instantToLdapDate(ZonedDateTime instant) {
-               return utcLdapDate.format(instant.withZoneSameInstant(ZoneOffset.UTC));
-       }
-
-       public static String getQueryValue(Map<String, List<String>> query, String key) {
-               if (!query.containsKey(key))
-                       return null;
-               List<String> val = query.get(key);
-               if (val.size() == 1)
-                       return val.get(0);
-               else
-                       throw new IllegalArgumentException("There are " + val.size() + " value(s) for " + key);
-       }
-
-       public static Map<String, List<String>> queryToMap(URI uri) {
-               return queryToMap(uri.getQuery());
-       }
-
-       private static Map<String, List<String>> queryToMap(String queryPart) {
-               try {
-                       final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
-                       if (queryPart == null)
-                               return query_pairs;
-                       final String[] pairs = queryPart.split("&");
-                       for (String pair : pairs) {
-                               final int idx = pair.indexOf("=");
-                               final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8.name())
-                                               : pair;
-                               if (!query_pairs.containsKey(key)) {
-                                       query_pairs.put(key, new LinkedList<String>());
-                               }
-                               final String value = idx > 0 && pair.length() > idx + 1
-                                               ? URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8.name())
-                                               : null;
-                               query_pairs.get(key).add(value);
-                       }
-                       return query_pairs;
-               } catch (UnsupportedEncodingException e) {
-                       throw new IllegalArgumentException("Cannot convert " + queryPart + " to map", e);
-               }
-       }
-
-       private NamingUtils() {
-
-       }
-
-       public static void main(String args[]) {
-               ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC);
-               String str = utcLdapDate.format(now);
-               System.out.println(str);
-               utcLdapDate.parse(str);
-               utcLdapDate.parse("19520512000000Z");
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/naming/NodeOID.java b/org.argeo.util/src/org/argeo/util/naming/NodeOID.java
deleted file mode 100644 (file)
index ea163d6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.argeo.util.naming;
-
-interface NodeOID {
-       String BASE = "1.3.6.1.4.1" + ".48308" + ".1";
-
-       // uuidgen --md5 --namespace @oid --name 1.3.6.1.4.1.48308
-       String BASE_UUID_V3 = "6869e86b-96b7-3d49-b6ab-ffffc5ad95fb";
-       
-       // uuidgen --sha1 --namespace @oid --name 1.3.6.1.4.1.48308
-       String BASE_UUID_V5 = "58873947-460c-59a6-a7b4-28a97def5f27";
-       
-       // ATTRIBUTE TYPES
-       String ATTRIBUTE_TYPES = BASE + ".4";
-
-       // OBJECT CLASSES
-       String OBJECT_CLASSES = BASE + ".6";
-}
diff --git a/org.argeo.util/src/org/argeo/util/naming/SpecifiedName.java b/org.argeo.util/src/org/argeo/util/naming/SpecifiedName.java
deleted file mode 100644 (file)
index 22f2a2d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.argeo.util.naming;
-
-/**
- * A name which has been specified and for which an id has been defined
- * (typically an OID).
- */
-public interface SpecifiedName {
-       /** The name */
-       String name();
-
-       /** An RFC or the URLof some specification */
-       default String getSpec() {
-               return null;
-       }
-
-       /** Typically an OID */
-       default String getID() {
-               return getClass().getName() + "." + name();
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/naming/dns/DnsBrowser.java b/org.argeo.util/src/org/argeo/util/naming/dns/DnsBrowser.java
deleted file mode 100644 (file)
index 4fba434..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-package org.argeo.util.naming.dns;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.SortedSet;
-import java.util.StringJoiner;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import javax.naming.Binding;
-import javax.naming.Context;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-public class DnsBrowser implements Closeable {
-       private final DirContext initialCtx;
-
-       public DnsBrowser() {
-               this(new ArrayList<>());
-       }
-
-       public DnsBrowser(List<String> dnsServerUrls) {
-               try {
-                       Objects.requireNonNull(dnsServerUrls);
-                       Hashtable<String, Object> env = new Hashtable<>();
-                       env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
-                       if (!dnsServerUrls.isEmpty()) {
-                               boolean specified = false;
-                               StringJoiner providerUrl = new StringJoiner(" ");
-                               for (String dnsUrl : dnsServerUrls) {
-                                       if (dnsUrl != null) {
-                                               providerUrl.add(dnsUrl);
-                                               specified = true;
-                                       }
-                               }
-                               if (specified)
-                                       env.put(Context.PROVIDER_URL, providerUrl.toString());
-                       }
-                       initialCtx = new InitialDirContext(env);
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot initialise DNS borowser.", e);
-               }
-       }
-
-       public Map<String, List<String>> getAllRecords(String name) {
-               try {
-                       Map<String, List<String>> res = new TreeMap<>();
-                       Attributes attrs = initialCtx.getAttributes(name);
-                       NamingEnumeration<String> ids = attrs.getIDs();
-                       while (ids.hasMore()) {
-                               String recordType = ids.next();
-                               List<String> lst = new ArrayList<String>();
-                               res.put(recordType, lst);
-                               Attribute attr = attrs.get(recordType);
-                               addValues(attr, lst);
-                       }
-                       return Collections.unmodifiableMap(res);
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get allrecords of " + name, e);
-               }
-       }
-
-       /**
-        * Return a single record (typically A, AAAA, etc. or null if not available.
-        * Will fail if multiple records.
-        */
-       public String getRecord(String name, String recordType) {
-               try {
-                       Attributes attrs = initialCtx.getAttributes(name, new String[] { recordType });
-                       if (attrs.size() == 0)
-                               return null;
-                       Attribute attr = attrs.get(recordType);
-                       if (attr.size() > 1)
-                               throw new IllegalArgumentException("Multiple record type " + recordType);
-                       assert attr.size() != 0;
-                       Object value = attr.get();
-                       assert value != null;
-                       return value.toString();
-               } catch (NameNotFoundException e) {
-                       return null;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get DNS entry " + recordType + " of " + name, e);
-               }
-       }
-
-       /**
-        * Return records of a given type.
-        */
-       public List<String> getRecords(String name, String recordType) {
-               try {
-                       List<String> res = new ArrayList<String>();
-                       Attributes attrs = initialCtx.getAttributes(name, new String[] { recordType });
-                       Attribute attr = attrs.get(recordType);
-                       addValues(attr, res);
-                       return res;
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot get records " + recordType + " of " + name, e);
-               }
-       }
-
-       /** Ordered, with preferred first. */
-       public List<String> getSrvRecordsAsHosts(String name, boolean withPort) {
-               List<String> raw = getRecords(name, "SRV");
-               if (raw.size() == 0)
-                       return null;
-               SortedSet<SrvRecord> res = new TreeSet<>();
-               for (int i = 0; i < raw.size(); i++) {
-                       String record = raw.get(i);
-                       String[] arr = record.split(" ");
-                       Integer priority = Integer.parseInt(arr[0]);
-                       Integer weight = Integer.parseInt(arr[1]);
-                       Integer port = Integer.parseInt(arr[2]);
-                       String hostname = arr[3];
-                       SrvRecord order = new SrvRecord(priority, weight, port, hostname);
-                       res.add(order);
-               }
-               List<String> lst = new ArrayList<>();
-               for (SrvRecord order : res) {
-                       lst.add(order.toHost(withPort));
-               }
-               return Collections.unmodifiableList(lst);
-       }
-
-       private void addValues(Attribute attr, List<String> lst) throws NamingException {
-               NamingEnumeration<?> values = attr.getAll();
-               while (values.hasMore()) {
-                       Object value = values.next();
-                       if (value != null) {
-                               if (value instanceof byte[]) {
-                                       String str = Base64.getEncoder().encodeToString((byte[]) value);
-                                       lst.add(str);
-                               } else
-                                       lst.add(value.toString());
-                       }
-               }
-
-       }
-
-       public List<String> listEntries(String name) {
-               try {
-                       List<String> res = new ArrayList<String>();
-                       NamingEnumeration<Binding> ne = initialCtx.listBindings(name);
-                       while (ne.hasMore()) {
-                               Binding b = ne.next();
-                               res.add(b.getName());
-                       }
-                       return Collections.unmodifiableList(res);
-               } catch (NamingException e) {
-                       throw new IllegalStateException("Cannot list entries of " + name, e);
-               }
-       }
-
-       @Override
-       public void close() throws IOException {
-               destroy();
-       }
-
-       public void destroy() {
-               try {
-                       initialCtx.close();
-               } catch (NamingException e) {
-                       // silent
-               }
-       }
-
-       public static void main(String[] args) {
-               if (args.length == 0) {
-                       printUsage(System.err);
-                       System.exit(1);
-               }
-               try (DnsBrowser dnsBrowser = new DnsBrowser()) {
-                       String hostname = args[0];
-                       String recordType = args.length > 1 ? args[1] : "A";
-                       if (recordType.equals("*")) {
-                               Map<String, List<String>> records = dnsBrowser.getAllRecords(hostname);
-                               for (String type : records.keySet()) {
-                                       for (String record : records.get(type)) {
-                                               String typeLabel;
-                                               if ("44".equals(type))
-                                                       typeLabel = "SSHFP";
-                                               else if ("46".equals(type))
-                                                       typeLabel = "RRSIG";
-                                               else if ("48".equals(type))
-                                                       typeLabel = "DNSKEY";
-                                               else
-                                                       typeLabel = type;
-                                               System.out.println(typeLabel + "\t" + record);
-                                       }
-                               }
-                       } else {
-                               System.out.println(dnsBrowser.getRecord(hostname, recordType));
-                       }
-
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-       }
-
-       public static void printUsage(PrintStream out) {
-               out.println("java org.argeo.naming.DnsBrowser <hostname> [<record type> | *]");
-       }
-
-}
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/util/naming/dns/SrvRecord.java b/org.argeo.util/src/org/argeo/util/naming/dns/SrvRecord.java
deleted file mode 100644 (file)
index ea6f3cc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.argeo.util.naming.dns;
-
-class SrvRecord implements Comparable<SrvRecord> {
-       private final Integer priority;
-       private final Integer weight;
-       private final Integer port;
-       private final String hostname;
-
-       public SrvRecord(Integer priority, Integer weight, Integer port, String hostname) {
-               this.priority = priority;
-               this.weight = weight;
-               this.port = port;
-               this.hostname = hostname;
-       }
-
-       @Override
-       public int compareTo(SrvRecord other) {
-               // https: // en.wikipedia.org/wiki/SRV_record
-               if (priority != other.priority)
-                       return priority - other.priority;
-               if (weight != other.weight)
-                       return other.weight - other.weight;
-               String host = toHost(false);
-               String otherHost = other.toHost(false);
-               if (host.length() == otherHost.length())
-                       return host.compareTo(otherHost);
-               else
-                       return host.length() - otherHost.length();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj instanceof SrvRecord) {
-                       SrvRecord other = (SrvRecord) obj;
-                       return priority == other.priority && weight == other.weight && port == other.port
-                                       && hostname.equals(other.hostname);
-               }
-               return false;
-       }
-
-       @Override
-       public String toString() {
-               return priority + " " + weight;
-       }
-
-       public String toHost(boolean withPort) {
-               String hostStr = hostname;
-               if (hostname.charAt(hostname.length() - 1) == '.')
-                       hostStr = hostname.substring(0, hostname.length() - 1);
-               return hostStr + (withPort ? ":" + port : "");
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/naming/package-info.java b/org.argeo.util/src/org/argeo/util/naming/package-info.java
deleted file mode 100644 (file)
index f62af36..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic naming and LDAP support. */
-package org.argeo.util.naming;
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/util/package-info.java b/org.argeo.util/src/org/argeo/util/package-info.java
deleted file mode 100644 (file)
index 4354b0a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic Java utilities. */
-package org.argeo.util;
\ No newline at end of file
diff --git a/org.argeo.util/src/org/argeo/util/register/Component.java b/org.argeo.util/src/org/argeo/util/register/Component.java
deleted file mode 100644 (file)
index 275811e..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-package org.argeo.util.register;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-/**
- * A wrapper for an object, whose dependencies and life cycle can be managed.
- */
-public class Component<I> implements Supplier<I>, Comparable<Component<?>> {
-
-       private final I instance;
-
-       private final Runnable init;
-       private final Runnable close;
-
-       private final Map<Class<? super I>, PublishedType<? super I>> types;
-       private final Set<Dependency<?>> dependencies;
-       private final Map<String, Object> properties;
-
-       private CompletableFuture<Void> activationStarted = null;
-       private CompletableFuture<Void> activated = null;
-
-       private CompletableFuture<Void> deactivationStarted = null;
-       private CompletableFuture<Void> deactivated = null;
-
-       // internal
-       private Set<Dependency<?>> dependants = new HashSet<>();
-
-       private RankingKey rankingKey;
-
-       Component(ComponentRegister register, I instance, Runnable init, Runnable close, Set<Dependency<?>> dependencies,
-                       Set<Class<? super I>> classes, Map<String, Object> properties) {
-               assert instance != null;
-               assert init != null;
-               assert close != null;
-               assert dependencies != null;
-               assert classes != null;
-
-               this.instance = instance;
-               this.init = init;
-               this.close = close;
-
-               // types
-               Map<Class<? super I>, PublishedType<? super I>> types = new HashMap<>(classes.size());
-               for (Class<? super I> clss : classes) {
-//                     if (!clss.isAssignableFrom(instance.getClass()))
-//                             throw new IllegalArgumentException(
-//                                             "Type " + clss.getName() + " is not compatible with " + instance.getClass().getName());
-                       types.put(clss, new PublishedType<>(this, clss));
-               }
-               this.types = Collections.unmodifiableMap(types);
-
-               // dependencies
-               this.dependencies = Collections.unmodifiableSet(new HashSet<>(dependencies));
-               for (Dependency<?> dependency : this.dependencies) {
-                       dependency.setDependantComponent(this);
-               }
-
-               // deactivated by default
-               deactivated = CompletableFuture.completedFuture(null);
-               deactivationStarted = CompletableFuture.completedFuture(null);
-
-               // TODO check whether context is active, so that we start right away
-               prepareNextActivation();
-
-               long serviceId = register.register(this);
-               Map<String, Object> props = new HashMap<>(properties);
-               props.put(RankingKey.SERVICE_ID, serviceId);
-               this.properties = Collections.unmodifiableMap(props);
-               rankingKey = new RankingKey(properties);
-       }
-
-       private void prepareNextActivation() {
-               activationStarted = new CompletableFuture<Void>();
-               activated = activationStarted //
-                               .thenComposeAsync(this::dependenciesActivated) //
-                               .thenRun(this.init) //
-                               .thenRun(() -> prepareNextDeactivation());
-       }
-
-       private void prepareNextDeactivation() {
-               deactivationStarted = new CompletableFuture<Void>();
-               deactivated = deactivationStarted //
-                               .thenComposeAsync(this::dependantsDeactivated) //
-                               .thenRun(this.close) //
-                               .thenRun(() -> prepareNextActivation());
-       }
-
-       CompletableFuture<Void> getActivated() {
-               return activated;
-       }
-
-       CompletableFuture<Void> getDeactivated() {
-               return deactivated;
-       }
-
-       void startActivating() {
-               if (activated.isDone() || activationStarted.isDone())
-                       return;
-               activationStarted.complete(null);
-       }
-
-       void startDeactivating() {
-               if (deactivated.isDone() || deactivationStarted.isDone())
-                       return;
-               deactivationStarted.complete(null);
-       }
-
-       CompletableFuture<Void> dependenciesActivated(Void v) {
-               Set<CompletableFuture<?>> constraints = new HashSet<>(this.dependencies.size());
-               for (Dependency<?> dependency : this.dependencies) {
-                       CompletableFuture<Void> dependencyActivated = dependency.publisherActivated() //
-                                       .thenCompose(dependency::set);
-                       constraints.add(dependencyActivated);
-               }
-               return CompletableFuture.allOf(constraints.toArray(new CompletableFuture[constraints.size()]));
-       }
-
-       CompletableFuture<Void> dependantsDeactivated(Void v) {
-               Set<CompletableFuture<?>> constraints = new HashSet<>(this.dependants.size());
-               for (Dependency<?> dependant : this.dependants) {
-                       CompletableFuture<Void> dependantDeactivated = dependant.dependantDeactivated() //
-                                       .thenCompose(dependant::unset);
-                       constraints.add(dependantDeactivated);
-               }
-               CompletableFuture<Void> dependantsDeactivated = CompletableFuture
-                               .allOf(constraints.toArray(new CompletableFuture[constraints.size()]));
-               return dependantsDeactivated;
-
-       }
-
-       void addDependant(Dependency<?> dependant) {
-               dependants.add(dependant);
-       }
-
-       @Override
-       public I get() {
-               return instance;
-       }
-
-       @SuppressWarnings("unchecked")
-       public <T> PublishedType<T> getType(Class<T> clss) {
-               if (!types.containsKey(clss))
-                       throw new IllegalArgumentException(clss.getName() + " is not a type published by this component");
-               return (PublishedType<T>) types.get(clss);
-       }
-
-       public <T> boolean isPublishedType(Class<T> clss) {
-               return types.containsKey(clss);
-       }
-
-       public Map<String, Object> getProperties() {
-               return properties;
-       }
-
-       @Override
-       public int compareTo(Component<?> o) {
-               return rankingKey.compareTo(rankingKey);
-       }
-
-       @Override
-       public int hashCode() {
-               Long serviceId = (Long) properties.get(RankingKey.SERVICE_ID);
-               if (serviceId != null)
-                       return serviceId.intValue();
-               else
-                       return super.hashCode();
-       }
-
-       @Override
-       public String toString() {
-               List<String> classes = new ArrayList<>();
-               for (Class<?> clss : types.keySet()) {
-                       classes.add(clss.getName());
-               }
-               return "Component " + classes + " " + properties + "";
-       }
-
-       /** A type which has been explicitly exposed by a component. */
-       public static class PublishedType<T> {
-               private Component<? extends T> component;
-               private Class<T> clss;
-
-               private CompletableFuture<T> value;
-
-               public PublishedType(Component<? extends T> component, Class<T> clss) {
-                       this.clss = clss;
-                       this.component = component;
-                       value = CompletableFuture.completedFuture((T) component.instance);
-               }
-
-               public Component<?> getPublisher() {
-                       return component;
-               }
-
-               public Class<T> getType() {
-                       return clss;
-               }
-
-               public CompletionStage<T> getValue() {
-                       return value.minimalCompletionStage();
-               }
-       }
-
-       /** Builds a {@link Component}. */
-       public static class Builder<I> implements Supplier<I> {
-               private final I instance;
-
-               private Runnable init;
-               private Runnable close;
-
-               private Set<Dependency<?>> dependencies = new HashSet<>();
-               private Set<Class<? super I>> types = new HashSet<>();
-               private final Map<String, Object> properties = new HashMap<>();
-
-               public Builder(I instance) {
-                       this.instance = instance;
-               }
-
-               public Component<I> build(ComponentRegister register) {
-                       // default values
-                       if (types.isEmpty()) {
-                               types.add(getInstanceClass());
-                       }
-
-                       if (init == null)
-                               init = () -> {
-                               };
-                       if (close == null)
-                               close = () -> {
-                               };
-
-                       // instantiation
-                       Component<I> component = new Component<I>(register, instance, init, close, dependencies, types, properties);
-                       for (Dependency<?> dependency : dependencies) {
-                               dependency.type.getPublisher().addDependant(dependency);
-                       }
-                       return component;
-               }
-
-               public Builder<I> addType(Class<? super I> clss) {
-                       types.add(clss);
-                       return this;
-               }
-
-               public Builder<I> addActivation(Runnable init) {
-                       if (this.init != null)
-                               throw new IllegalArgumentException("init method is already set");
-                       this.init = init;
-                       return this;
-               }
-
-               public Builder<I> addDeactivation(Runnable close) {
-                       if (this.close != null)
-                               throw new IllegalArgumentException("close method is already set");
-                       this.close = close;
-                       return this;
-               }
-
-               public <D> Builder<I> addDependency(PublishedType<D> type, Consumer<D> set, Consumer<D> unset) {
-                       dependencies.add(new Dependency<D>(type, set, unset));
-                       return this;
-               }
-
-               public void addProperty(String key, Object value) {
-                       if (properties.containsKey(key))
-                               throw new IllegalStateException("Key " + key + " is already set.");
-                       properties.put(key, value);
-               }
-
-               @Override
-               public I get() {
-                       return instance;
-               }
-
-               @SuppressWarnings("unchecked")
-               private Class<I> getInstanceClass() {
-                       return (Class<I>) instance.getClass();
-               }
-
-       }
-
-       static class Dependency<D> {
-               private PublishedType<D> type;
-               private Consumer<D> set;
-               private Consumer<D> unset;
-
-               // live
-               Component<?> dependantComponent;
-               CompletableFuture<Void> setStage;
-               CompletableFuture<Void> unsetStage;
-
-               public Dependency(PublishedType<D> types, Consumer<D> set, Consumer<D> unset) {
-                       super();
-                       this.type = types;
-                       this.set = set != null ? set : t -> {
-                       };
-                       this.unset = unset != null ? unset : t -> {
-                       };
-               }
-
-               // live
-               void setDependantComponent(Component<?> component) {
-                       this.dependantComponent = component;
-               }
-
-               CompletableFuture<Void> publisherActivated() {
-                       return type.getPublisher().activated.copy();
-               }
-
-               CompletableFuture<Void> dependantDeactivated() {
-                       return dependantComponent.deactivated.copy();
-               }
-
-               CompletableFuture<Void> set(Void v) {
-                       return type.value.thenAccept(set);
-               }
-
-               CompletableFuture<Void> unset(Void v) {
-                       return type.value.thenAccept(unset);
-               }
-
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/register/ComponentRegister.java b/org.argeo.util/src/org/argeo/util/register/ComponentRegister.java
deleted file mode 100644 (file)
index d78b6ba..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.argeo.util.register;
-
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.function.Predicate;
-
-/** A register of components which can coordinate their activation. */
-public interface ComponentRegister {
-       long register(Component<?> component);
-
-       <T> SortedSet<Component<? extends T>> find(Class<T> clss, Predicate<Map<String, Object>> filter);
-
-       default <T> Component.PublishedType<T> getSingleton(Class<T> type) {
-               SortedSet<Component<? extends T>> found = find(type, null);
-               if (found.size() == 0)
-                       throw new IllegalStateException("No component found for " + type);
-               return found.first().getType(type);
-       }
-
-       default <T> T getObject(Class<T> clss) {
-               SortedSet<Component<? extends T>> found = find(clss, null);
-               if (found.size() == 0)
-                       return null;
-               return found.first().get();
-       }
-
-       Component<?> get(Object instance);
-
-//     default <T> PublishedType<T> getType(Class<T> clss) {
-//             SortedSet<Component<? extends T>> components = find(clss, null);
-//             if (components.size() == 0)
-//                     return null;
-//             return components.first().getType(clss);
-//     }
-
-       void activate();
-
-       void deactivate();
-
-       boolean isActive();
-
-       void clear();
-}
diff --git a/org.argeo.util/src/org/argeo/util/register/RankingKey.java b/org.argeo.util/src/org/argeo/util/register/RankingKey.java
deleted file mode 100644 (file)
index 7a43e35..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-package org.argeo.util.register;
-
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Key used to classify and filter available components.
- */
-public class RankingKey implements Comparable<RankingKey> {
-       public final static String SERVICE_PID = "service.pid";
-       public final static String SERVICE_ID = "service.id";
-       public final static String SERVICE_RANKING = "service.ranking";
-
-       private String pid;
-       private Integer ranking = 0;
-       private Long id = 0l;
-
-       public RankingKey(String pid, Integer ranking, Long id) {
-               super();
-               this.pid = pid;
-               this.ranking = ranking;
-               this.id = id;
-       }
-
-       public RankingKey(Map<String, Object> properties) {
-               this.pid = properties.containsKey(SERVICE_PID) ? properties.get(SERVICE_PID).toString() : null;
-               this.ranking = properties.containsKey(SERVICE_RANKING)
-                               ? Integer.parseInt(properties.get(SERVICE_RANKING).toString())
-                               : 0;
-               this.id = properties.containsKey(SERVICE_ID) ? (Long) properties.get(SERVICE_ID) : null;
-       }
-
-       @Override
-       public int hashCode() {
-               Integer result = 0;
-               if (pid != null)
-                       result = +pid.hashCode();
-               if (ranking != null)
-                       result = +ranking;
-               return result;
-       }
-
-       @Override
-       protected Object clone() throws CloneNotSupportedException {
-               return new RankingKey(pid, ranking, id);
-       }
-
-       @Override
-       public String toString() {
-               StringBuilder sb = new StringBuilder("");
-               if (pid != null)
-                       sb.append(pid);
-               if (ranking != null && ranking != 0)
-                       sb.append(' ').append(ranking);
-               return sb.toString();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (!(obj instanceof RankingKey))
-                       return false;
-               RankingKey other = (RankingKey) obj;
-               return Objects.equals(pid, other.pid) && Objects.equals(ranking, other.ranking) && Objects.equals(id, other.id);
-       }
-
-       @Override
-       public int compareTo(RankingKey o) {
-               if (pid != null && o.pid != null) {
-                       if (pid.equals(o.pid)) {
-                               if (ranking.equals(o.ranking))
-                                       if (id != null && o.id != null)
-                                               return id.compareTo(o.id);
-                                       else
-                                               return 0;
-                               else
-                                       return ranking.compareTo(o.ranking);
-                       } else {
-                               return pid.compareTo(o.pid);
-                       }
-
-               } else {
-               }
-               return -1;
-       }
-
-       public String getPid() {
-               return pid;
-       }
-
-       public Integer getRanking() {
-               return ranking;
-       }
-
-       public Long getId() {
-               return id;
-       }
-
-       public static RankingKey minPid(String pid) {
-               return new RankingKey(pid, Integer.MIN_VALUE, null);
-       }
-
-       public static RankingKey maxPid(String pid) {
-               return new RankingKey(pid, Integer.MAX_VALUE, null);
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/register/SimpleRegister.java b/org.argeo.util/src/org/argeo/util/register/SimpleRegister.java
deleted file mode 100644 (file)
index 7aa9ebe..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-package org.argeo.util.register;
-
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Predicate;
-
-/** A minimal component register. */
-public class SimpleRegister implements ComponentRegister {
-       private final AtomicBoolean started = new AtomicBoolean(false);
-       private final IdentityHashMap<Object, Component<?>> components = new IdentityHashMap<>();
-       private final AtomicLong nextServiceId = new AtomicLong(0l);
-
-       @Override
-       public long register(Component<?> component) {
-               return registerComponent(component);
-       }
-
-       @SuppressWarnings({ "unchecked" })
-       @Override
-       public synchronized <T> SortedSet<Component<? extends T>> find(Class<T> clss,
-                       Predicate<Map<String, Object>> filter) {
-               SortedSet<Component<? extends T>> result = new TreeSet<>();
-               instances: for (Object instance : components.keySet()) {
-                       if (!clss.isAssignableFrom(instance.getClass()))
-                               continue instances;
-                       Component<? extends T> component = (Component<? extends T>) components.get(instance);
-
-                       if (component.isPublishedType(clss)) {
-                               if (filter != null) {
-                                       filter.test(component.getProperties());
-                               }
-                               result.add(component);
-                       }
-               }
-               if (result.isEmpty())
-                       return null;
-               return result;
-
-       }
-
-       synchronized long registerComponent(Component<?> component) {
-               if (started.get()) // TODO make it really dynamic
-                       throw new IllegalStateException("Already activated");
-               if (components.containsKey(component.get()))
-                       throw new IllegalArgumentException("Already registered as component");
-               components.put(component.get(), component);
-               return nextServiceId.incrementAndGet();
-       }
-
-       @Override
-       public synchronized Component<?> get(Object instance) {
-               if (!components.containsKey(instance))
-                       throw new IllegalArgumentException("Not registered as component");
-               return components.get(instance);
-       }
-
-       @Override
-       public synchronized void activate() {
-               if (started.get())
-                       throw new IllegalStateException("Already activated");
-               Set<CompletableFuture<?>> constraints = new HashSet<>();
-               for (Component<?> component : components.values()) {
-                       component.startActivating();
-                       constraints.add(component.getActivated());
-               }
-
-               // wait
-               try {
-                       CompletableFuture.allOf(constraints.toArray(new CompletableFuture[0])).thenRun(() -> started.set(true))
-                                       .get();
-               } catch (InterruptedException e) {
-                       throw new RuntimeException("Register activation has been interrupted", e);
-               } catch (ExecutionException e) {
-                       if (RuntimeException.class.isAssignableFrom(e.getCause().getClass())) {
-                               throw (RuntimeException) e.getCause();
-                       } else {
-                               throw new IllegalStateException("Cannot activate register", e.getCause());
-                       }
-               }
-       }
-
-       @Override
-       public synchronized void deactivate() {
-               if (!started.get())
-                       throw new IllegalStateException("Not activated");
-               Set<CompletableFuture<?>> constraints = new HashSet<>();
-               for (Component<?> component : components.values()) {
-                       component.startDeactivating();
-                       constraints.add(component.getDeactivated());
-               }
-
-               // wait
-               try {
-                       CompletableFuture.allOf(constraints.toArray(new CompletableFuture[0])).thenRun(() -> started.set(false))
-                                       .get();
-               } catch (InterruptedException e) {
-                       throw new RuntimeException("Register deactivation has been interrupted", e);
-               } catch (ExecutionException e) {
-                       if (RuntimeException.class.isAssignableFrom(e.getCause().getClass())) {
-                               throw (RuntimeException) e.getCause();
-                       } else {
-                               throw new IllegalStateException("Cannot deactivate register", e.getCause());
-                       }
-               }
-       }
-
-       @Override
-       public synchronized boolean isActive() {
-               return started.get();
-       }
-
-       @Override
-       public synchronized void clear() {
-               components.clear();
-       }
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/AbstractWorkingCopy.java b/org.argeo.util/src/org/argeo/util/transaction/AbstractWorkingCopy.java
deleted file mode 100644 (file)
index 0da35ac..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.argeo.util.transaction;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public abstract class AbstractWorkingCopy<DATA, ATTR, ID> implements WorkingCopy<DATA, ATTR, ID> {
-       private Map<ID, DATA> newData = new HashMap<ID, DATA>();
-       private Map<ID, ATTR> modifiedData = new HashMap<ID, ATTR>();
-       private Map<ID, DATA> deletedData = new HashMap<ID, DATA>();
-
-       protected abstract ID getId(DATA data);
-
-       protected abstract ATTR cloneAttributes(DATA data);
-
-       public void cleanUp() {
-               // clean collections
-               newData.clear();
-               newData = null;
-               modifiedData.clear();
-               modifiedData = null;
-               deletedData.clear();
-               deletedData = null;
-       }
-
-       public boolean noModifications() {
-               return newData.size() == 0 && modifiedData.size() == 0 && deletedData.size() == 0;
-       }
-
-       public void startEditing(DATA user) {
-               ID id = getId(user);
-               if (modifiedData.containsKey(id))
-                       throw new IllegalStateException("Already editing " + id);
-               modifiedData.put(id, cloneAttributes(user));
-       }
-
-       public Map<ID, DATA> getNewData() {
-               return newData;
-       }
-
-       public Map<ID, DATA> getDeletedData() {
-               return deletedData;
-       }
-
-       public Map<ID, ATTR> getModifiedData() {
-               return modifiedData;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/JtaStatusAdapter.java b/org.argeo.util/src/org/argeo/util/transaction/JtaStatusAdapter.java
deleted file mode 100644 (file)
index bd97706..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.argeo.util.transaction;
-
-/** JTA transaction status. */
-public class JtaStatusAdapter implements TransactionStatusAdapter<Integer> {
-       private static final Integer STATUS_ACTIVE = 0;
-       private static final Integer STATUS_COMMITTED = 3;
-       private static final Integer STATUS_COMMITTING = 8;
-       private static final Integer STATUS_MARKED_ROLLBACK = 1;
-       private static final Integer STATUS_NO_TRANSACTION = 6;
-       private static final Integer STATUS_PREPARED = 2;
-       private static final Integer STATUS_PREPARING = 7;
-       private static final Integer STATUS_ROLLEDBACK = 4;
-       private static final Integer STATUS_ROLLING_BACK = 9;
-//     private static final Integer STATUS_UNKNOWN = 5;
-
-       @Override
-       public Integer getActiveStatus() {
-               return STATUS_ACTIVE;
-       }
-
-       @Override
-       public Integer getPreparingStatus() {
-               return STATUS_PREPARING;
-       }
-
-       @Override
-       public Integer getMarkedRollbackStatus() {
-               return STATUS_MARKED_ROLLBACK;
-       }
-
-       @Override
-       public Integer getPreparedStatus() {
-               return STATUS_PREPARED;
-       }
-
-       @Override
-       public Integer getCommittingStatus() {
-               return STATUS_COMMITTING;
-       }
-
-       @Override
-       public Integer getCommittedStatus() {
-               return STATUS_COMMITTED;
-       }
-
-       @Override
-       public Integer getRollingBackStatus() {
-               return STATUS_ROLLING_BACK;
-       }
-
-       @Override
-       public Integer getRolledBackStatus() {
-               return STATUS_ROLLEDBACK;
-       }
-
-       @Override
-       public Integer getNoTransactionStatus() {
-               return STATUS_NO_TRANSACTION;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/SimpleRollbackException.java b/org.argeo.util/src/org/argeo/util/transaction/SimpleRollbackException.java
deleted file mode 100644 (file)
index 010b549..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.util.transaction;
-
-/** Internal unchecked rollback exception. */
-class SimpleRollbackException extends RuntimeException {
-       private static final long serialVersionUID = 8055601819719780566L;
-
-       public SimpleRollbackException() {
-               super();
-       }
-
-       public SimpleRollbackException(Throwable cause) {
-               super(cause);
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/SimpleTransaction.java b/org.argeo.util/src/org/argeo/util/transaction/SimpleTransaction.java
deleted file mode 100644 (file)
index 56ef063..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.argeo.util.transaction;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.XAResource;
-import javax.transaction.xa.Xid;
-
-/** Simple implementation of an XA transaction. */
-class SimpleTransaction<T>
-//implements Transaction, Status 
-{
-       private final Xid xid;
-       private T status;
-       private final List<XAResource> xaResources = new ArrayList<XAResource>();
-
-       private final SimpleTransactionManager transactionManager;
-       private TransactionStatusAdapter<T> tsa;
-
-       public SimpleTransaction(SimpleTransactionManager transactionManager, TransactionStatusAdapter<T> tsa) {
-               this.tsa = tsa;
-               this.status = tsa.getActiveStatus();
-               this.xid = new UuidXid();
-               this.transactionManager = transactionManager;
-       }
-
-       public synchronized void commit()
-//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
-//                     SecurityException, IllegalStateException, SystemException 
-       {
-               status = tsa.getPreparingStatus();
-               for (XAResource xaRes : xaResources) {
-                       if (status.equals(tsa.getMarkedRollbackStatus()))
-                               break;
-                       try {
-                               xaRes.prepare(xid);
-                       } catch (XAException e) {
-                               status = tsa.getMarkedRollbackStatus();
-                               error("Cannot prepare " + xaRes + " for " + xid, e);
-                       }
-               }
-               if (status.equals(tsa.getMarkedRollbackStatus())) {
-                       rollback();
-                       throw new SimpleRollbackException();
-               }
-               status = tsa.getPreparedStatus();
-
-               status = tsa.getCommittingStatus();
-               for (XAResource xaRes : xaResources) {
-                       if (status.equals(tsa.getMarkedRollbackStatus()))
-                               break;
-                       try {
-                               xaRes.commit(xid, false);
-                       } catch (XAException e) {
-                               status = tsa.getMarkedRollbackStatus();
-                               error("Cannot prepare " + xaRes + " for " + xid, e);
-                       }
-               }
-               if (status.equals(tsa.getMarkedRollbackStatus())) {
-                       rollback();
-                       throw new SimpleRollbackException();
-               }
-
-               // complete
-               status = tsa.getCommittedStatus();
-               clearResources(XAResource.TMSUCCESS);
-               transactionManager.unregister(xid);
-       }
-
-       public synchronized void rollback()
-//                     throws IllegalStateException, SystemException 
-       {
-               status = tsa.getRollingBackStatus();
-               for (XAResource xaRes : xaResources) {
-                       try {
-                               xaRes.rollback(xid);
-                       } catch (XAException e) {
-                               error("Cannot rollback " + xaRes + " for " + xid, e);
-                       }
-               }
-
-               // complete
-               status = tsa.getRolledBackStatus();
-               clearResources(XAResource.TMFAIL);
-               transactionManager.unregister(xid);
-       }
-
-       public synchronized boolean enlistResource(XAResource xaRes)
-//                     throws RollbackException, IllegalStateException, SystemException 
-       {
-               if (xaResources.add(xaRes)) {
-                       try {
-                               xaRes.start(getXid(), XAResource.TMNOFLAGS);
-                               return true;
-                       } catch (XAException e) {
-                               error("Cannot enlist " + xaRes, e);
-                               return false;
-                       }
-               } else
-                       return false;
-       }
-
-       public synchronized boolean delistResource(XAResource xaRes, int flag)
-//                     throws IllegalStateException, SystemException 
-       {
-               if (xaResources.remove(xaRes)) {
-                       try {
-                               xaRes.end(getXid(), flag);
-                       } catch (XAException e) {
-                               error("Cannot delist " + xaRes, e);
-                               return false;
-                       }
-                       return true;
-               } else
-                       return false;
-       }
-
-       protected void clearResources(int flag) {
-               for (XAResource xaRes : xaResources)
-                       try {
-                               xaRes.end(getXid(), flag);
-                       } catch (XAException e) {
-                               error("Cannot end " + xaRes, e);
-                       }
-               xaResources.clear();
-       }
-
-       protected void error(Object obj, Exception e) {
-               System.err.println(obj);
-               e.printStackTrace();
-       }
-
-       public synchronized T getStatus()
-//                     throws SystemException 
-       {
-               return status;
-       }
-
-//     public void registerSynchronization(Synchronization sync)
-//                     throws RollbackException, IllegalStateException, SystemException {
-//             throw new UnsupportedOperationException();
-//     }
-
-       public void setRollbackOnly()
-//                     throws IllegalStateException, SystemException 
-       {
-               status = tsa.getMarkedRollbackStatus();
-       }
-
-       @Override
-       public int hashCode() {
-               return xid.hashCode();
-       }
-
-       Xid getXid() {
-               return xid;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/SimpleTransactionManager.java b/org.argeo.util/src/org/argeo/util/transaction/SimpleTransactionManager.java
deleted file mode 100644 (file)
index f5be7c8..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-package org.argeo.util.transaction;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Callable;
-
-import javax.transaction.xa.XAResource;
-import javax.transaction.xa.Xid;
-
-/**
- * Simple implementation of an XA transaction manager.
- */
-public class SimpleTransactionManager
-// implements TransactionManager, UserTransaction 
-               implements WorkControl, WorkTransaction {
-       private ThreadLocal<SimpleTransaction<Integer>> current = new ThreadLocal<SimpleTransaction<Integer>>();
-
-       private Map<Xid, SimpleTransaction<Integer>> knownTransactions = Collections
-                       .synchronizedMap(new HashMap<Xid, SimpleTransaction<Integer>>());
-       private TransactionStatusAdapter<Integer> tsa = new JtaStatusAdapter();
-//     private SyncRegistry syncRegistry = new SyncRegistry();
-
-       /*
-        * WORK IMPLEMENTATION
-        */
-       @Override
-       public <T> T required(Callable<T> work) {
-               T res;
-               begin();
-               try {
-                       res = work.call();
-                       commit();
-               } catch (Exception e) {
-                       rollback();
-                       throw new SimpleRollbackException(e);
-               }
-               return res;
-       }
-
-       @Override
-       public WorkContext getWorkContext() {
-               return new WorkContext() {
-
-                       @Override
-                       public void registerXAResource(XAResource resource, String recoveryId) {
-                               getTransaction().enlistResource(resource);
-                       }
-               };
-       }
-
-       /*
-        * WORK TRANSACTION IMPLEMENTATION
-        */
-
-       @Override
-       public boolean isNoTransactionStatus() {
-               return tsa.getNoTransactionStatus().equals(getStatus());
-       }
-
-       /*
-        * JTA IMPLEMENTATION
-        */
-
-       public void begin()
-//                     throws NotSupportedException, SystemException 
-       {
-               if (getCurrent() != null)
-                       throw new UnsupportedOperationException("Nested transactions are not supported");
-               SimpleTransaction<Integer> transaction = new SimpleTransaction<Integer>(this, tsa);
-               knownTransactions.put(transaction.getXid(), transaction);
-               current.set(transaction);
-       }
-
-       public void commit()
-//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
-//                     SecurityException, IllegalStateException, SystemException 
-       {
-               if (getCurrent() == null)
-                       throw new IllegalStateException("No transaction registered with the current thread.");
-               getCurrent().commit();
-       }
-
-       public int getStatus()
-//                     throws SystemException
-       {
-               if (getCurrent() == null)
-                       return tsa.getNoTransactionStatus();
-               return getTransaction().getStatus();
-       }
-
-       public SimpleTransaction<Integer> getTransaction()
-//                     throws SystemException 
-       {
-               return getCurrent();
-       }
-
-       protected SimpleTransaction<Integer> getCurrent()
-//                     throws SystemException 
-       {
-               SimpleTransaction<Integer> transaction = current.get();
-               if (transaction == null)
-                       return null;
-               Integer status = transaction.getStatus();
-               if (status.equals(tsa.getCommittedStatus()) || status.equals(tsa.getRolledBackStatus())) {
-                       current.remove();
-                       return null;
-               }
-               return transaction;
-       }
-
-       void unregister(Xid xid) {
-               knownTransactions.remove(xid);
-       }
-
-       public void resume(SimpleTransaction<Integer> tobj)
-//                     throws InvalidTransactionException, IllegalStateException, SystemException 
-       {
-               if (getCurrent() != null)
-                       throw new IllegalStateException("Transaction " + current.get() + " already registered");
-               current.set(tobj);
-       }
-
-       public void rollback()
-//                     throws IllegalStateException, SecurityException, SystemException 
-       {
-               if (getCurrent() == null)
-                       throw new IllegalStateException("No transaction registered with the current thread.");
-               getCurrent().rollback();
-       }
-
-       public void setRollbackOnly()
-//                     throws IllegalStateException, SystemException 
-       {
-               if (getCurrent() == null)
-                       throw new IllegalStateException("No transaction registered with the current thread.");
-               getCurrent().setRollbackOnly();
-       }
-
-       public void setTransactionTimeout(int seconds)
-//                     throws SystemException
-       {
-               throw new UnsupportedOperationException();
-       }
-
-       public SimpleTransaction<Integer> suspend()
-//                     throws SystemException
-       {
-               SimpleTransaction<Integer> transaction = getCurrent();
-               current.remove();
-               return transaction;
-       }
-
-//     public TransactionSynchronizationRegistry getTsr() {
-//             return syncRegistry;
-//     }
-//
-//     private class SyncRegistry implements TransactionSynchronizationRegistry {
-//             @Override
-//             public Object getTransactionKey() {
-//                     try {
-//                             SimpleTransaction transaction = getCurrent();
-//                             if (transaction == null)
-//                                     return null;
-//                             return getCurrent().getXid();
-//                     } catch (SystemException e) {
-//                             throw new IllegalStateException("Cannot get transaction key", e);
-//                     }
-//             }
-//
-//             @Override
-//             public void putResource(Object key, Object value) {
-//                     throw new UnsupportedOperationException();
-//             }
-//
-//             @Override
-//             public Object getResource(Object key) {
-//                     throw new UnsupportedOperationException();
-//             }
-//
-//             @Override
-//             public void registerInterposedSynchronization(Synchronization sync) {
-//                     throw new UnsupportedOperationException();
-//             }
-//
-//             @Override
-//             public int getTransactionStatus() {
-//                     try {
-//                             return getStatus();
-//                     } catch (SystemException e) {
-//                             throw new IllegalStateException("Cannot get status", e);
-//                     }
-//             }
-//
-//             @Override
-//             public boolean getRollbackOnly() {
-//                     try {
-//                             return getStatus() == Status.STATUS_MARKED_ROLLBACK;
-//                     } catch (SystemException e) {
-//                             throw new IllegalStateException("Cannot get status", e);
-//                     }
-//             }
-//
-//             @Override
-//             public void setRollbackOnly() {
-//                     try {
-//                             getCurrent().setRollbackOnly();
-//                     } catch (Exception e) {
-//                             throw new IllegalStateException("Cannot set rollback only", e);
-//                     }
-//             }
-//
-//     }
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/TransactionStatusAdapter.java b/org.argeo.util/src/org/argeo/util/transaction/TransactionStatusAdapter.java
deleted file mode 100644 (file)
index a74fef1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.argeo.util.transaction;
-
-/** Abstract the various approaches to represent transaction status. */
-public interface TransactionStatusAdapter<T> {
-       T getActiveStatus();
-
-       T getPreparingStatus();
-
-       T getMarkedRollbackStatus();
-
-       T getPreparedStatus();
-
-       T getCommittingStatus();
-
-       T getCommittedStatus();
-
-       T getRollingBackStatus();
-
-       T getRolledBackStatus();
-
-       T getNoTransactionStatus();
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/UuidXid.java b/org.argeo.util/src/org/argeo/util/transaction/UuidXid.java
deleted file mode 100644 (file)
index b6acebe..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.argeo.util.transaction;
-
-import java.io.Serializable;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.UUID;
-
-import javax.transaction.xa.Xid;
-
-/**
- * Implementation of {@link Xid} based on {@link UUID}, using max significant
- * bits as global transaction id, and least significant bits as branch
- * qualifier.
- */
-public class UuidXid implements Xid, Serializable {
-       private static final long serialVersionUID = -5380531989917886819L;
-       public final static int FORMAT = (int) serialVersionUID;
-
-       private final static int BYTES_PER_LONG = Long.SIZE / Byte.SIZE;
-
-       private final int format;
-       private final byte[] globalTransactionId;
-       private final byte[] branchQualifier;
-       private final String uuid;
-       private final int hashCode;
-
-       public UuidXid() {
-               this(UUID.randomUUID());
-       }
-
-       public UuidXid(UUID uuid) {
-               this.format = FORMAT;
-               this.globalTransactionId = uuidToBytes(uuid.getMostSignificantBits());
-               this.branchQualifier = uuidToBytes(uuid.getLeastSignificantBits());
-               this.uuid = uuid.toString();
-               this.hashCode = uuid.hashCode();
-       }
-
-       public UuidXid(Xid xid) {
-               this(xid.getFormatId(), xid.getGlobalTransactionId(), xid
-                               .getBranchQualifier());
-       }
-
-       private UuidXid(int format, byte[] globalTransactionId,
-                       byte[] branchQualifier) {
-               this.format = format;
-               this.globalTransactionId = globalTransactionId;
-               this.branchQualifier = branchQualifier;
-               this.uuid = bytesToUUID(globalTransactionId, branchQualifier)
-                               .toString();
-               this.hashCode = uuid.hashCode();
-       }
-
-       @Override
-       public int getFormatId() {
-               return format;
-       }
-
-       @Override
-       public byte[] getGlobalTransactionId() {
-               return Arrays.copyOf(globalTransactionId, globalTransactionId.length);
-       }
-
-       @Override
-       public byte[] getBranchQualifier() {
-               return Arrays.copyOf(branchQualifier, branchQualifier.length);
-       }
-
-       @Override
-       public int hashCode() {
-               return hashCode;
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (this == obj)
-                       return true;
-               if (obj instanceof UuidXid) {
-                       UuidXid that = (UuidXid) obj;
-                       return Arrays.equals(globalTransactionId, that.globalTransactionId)
-                                       && Arrays.equals(branchQualifier, that.branchQualifier);
-               }
-               if (obj instanceof Xid) {
-                       Xid that = (Xid) obj;
-                       return Arrays.equals(globalTransactionId,
-                                       that.getGlobalTransactionId())
-                                       && Arrays
-                                                       .equals(branchQualifier, that.getBranchQualifier());
-               }
-               return uuid.equals(obj.toString());
-       }
-
-       @Override
-       protected Object clone() throws CloneNotSupportedException {
-               return new UuidXid(format, globalTransactionId, branchQualifier);
-       }
-
-       @Override
-       public String toString() {
-               return uuid;
-       }
-
-       public UUID asUuid() {
-               return bytesToUUID(globalTransactionId, branchQualifier);
-       }
-
-       public static byte[] uuidToBytes(long bits) {
-               ByteBuffer buffer = ByteBuffer.allocate(BYTES_PER_LONG);
-               buffer.putLong(0, bits);
-               return buffer.array();
-       }
-
-       public static UUID bytesToUUID(byte[] most, byte[] least) {
-               if (most.length < BYTES_PER_LONG)
-                       most = Arrays.copyOf(most, BYTES_PER_LONG);
-               if (least.length < BYTES_PER_LONG)
-                       least = Arrays.copyOf(least, BYTES_PER_LONG);
-               ByteBuffer buffer = ByteBuffer.allocate(2 * BYTES_PER_LONG);
-               buffer.put(most, 0, BYTES_PER_LONG);
-               buffer.put(least, 0, BYTES_PER_LONG);
-               buffer.flip();
-               return new UUID(buffer.getLong(), buffer.getLong());
-       }
-
-       // public static void main(String[] args) {
-       // UUID uuid = UUID.randomUUID();
-       // System.out.println(uuid);
-       // uuid = bytesToUUID(uuidToBytes(uuid.getMostSignificantBits()),
-       // uuidToBytes(uuid.getLeastSignificantBits()));
-       // System.out.println(uuid);
-       // }
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkContext.java b/org.argeo.util/src/org/argeo/util/transaction/WorkContext.java
deleted file mode 100644 (file)
index e818b83..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.argeo.util.transaction;
-
-import javax.transaction.xa.XAResource;
-
-/**
- * A minimalistic interface similar to OSGi transaction context in order to
- * register XA resources.
- */
-public interface WorkContext {
-       void registerXAResource(XAResource resource, String recoveryId);
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkControl.java b/org.argeo.util/src/org/argeo/util/transaction/WorkControl.java
deleted file mode 100644 (file)
index db0e475..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.util.transaction;
-
-import java.util.concurrent.Callable;
-
-/**
- * A minimalistic interface inspired by OSGi transaction control in order to
- * commit units of work externally.
- */
-public interface WorkControl {
-       <T> T required(Callable<T> work);
-
-       void setRollbackOnly();
-
-       WorkContext getWorkContext();
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkTransaction.java b/org.argeo.util/src/org/argeo/util/transaction/WorkTransaction.java
deleted file mode 100644 (file)
index 245ca41..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.util.transaction;
-
-/**
- * A minimalistic interface inspired by JTA user transaction in order to commit
- * units of work externally.
- */
-public interface WorkTransaction {
-       void begin();
-
-       void commit();
-
-       void rollback();
-
-       boolean isNoTransactionStatus();
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkingCopy.java b/org.argeo.util/src/org/argeo/util/transaction/WorkingCopy.java
deleted file mode 100644 (file)
index 9dd3fc5..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.argeo.util.transaction;
-
-import java.util.Map;
-
-public interface WorkingCopy<DATA, ATTR, ID> {
-       void startEditing(DATA user);
-
-       boolean noModifications();
-
-       void cleanUp();
-
-       Map<ID, DATA> getNewData();
-
-       Map<ID, DATA> getDeletedData();
-
-       Map<ID, ATTR> getModifiedData();
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkingCopyProcessor.java b/org.argeo.util/src/org/argeo/util/transaction/WorkingCopyProcessor.java
deleted file mode 100644 (file)
index cdd6404..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.argeo.util.transaction;
-
-public interface WorkingCopyProcessor<WC extends WorkingCopy<?, ?, ?>> {
-       void prepare(WC wc);
-
-       void commit(WC wc);
-
-       void rollback(WC wc);
-       
-       WC newWorkingCopy();
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkingCopyXaResource.java b/org.argeo.util/src/org/argeo/util/transaction/WorkingCopyXaResource.java
deleted file mode 100644 (file)
index ddb605a..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-package org.argeo.util.transaction;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.XAResource;
-import javax.transaction.xa.Xid;
-
-/** {@link XAResource} for a user directory being edited. */
-public class WorkingCopyXaResource<WC extends WorkingCopy<?, ?, ?>> implements XAResource {
-       private final WorkingCopyProcessor<WC> processor;
-
-       private Map<Xid, WC> workingCopies = new HashMap<Xid, WC>();
-       private Xid editingXid = null;
-       private int transactionTimeout = 0;
-
-       public WorkingCopyXaResource(WorkingCopyProcessor<WC> processor) {
-               this.processor = processor;
-       }
-
-       @Override
-       public synchronized void start(Xid xid, int flags) throws XAException {
-               if (editingXid != null)
-                       throw new IllegalStateException("Already editing " + editingXid);
-               WC wc = workingCopies.put(xid, processor.newWorkingCopy());
-               if (wc != null)
-                       throw new IllegalStateException("There is already a working copy for " + xid);
-               this.editingXid = xid;
-       }
-
-       @Override
-       public void end(Xid xid, int flags) throws XAException {
-               checkXid(xid);
-       }
-
-       private WC wc(Xid xid) {
-               return workingCopies.get(xid);
-       }
-
-       public synchronized WC wc() {
-               if (editingXid == null)
-                       return null;
-               WC wc = workingCopies.get(editingXid);
-               if (wc == null)
-                       throw new IllegalStateException("No working copy found for " + editingXid);
-               return wc;
-       }
-
-       private synchronized void cleanUp(Xid xid) {
-               WC wc = workingCopies.get(xid);
-               if (wc != null) {
-                       wc.cleanUp();
-                       workingCopies.remove(xid);
-               }
-               editingXid = null;
-       }
-
-       @Override
-       public int prepare(Xid xid) throws XAException {
-               checkXid(xid);
-               WC wc = wc(xid);
-               if (wc.noModifications())
-                       return XA_RDONLY;
-               try {
-                       processor.prepare(wc);
-               } catch (Exception e) {
-                       e.printStackTrace();
-                       throw new XAException(XAException.XAER_RMERR);
-               }
-               return XA_OK;
-       }
-
-       @Override
-       public void commit(Xid xid, boolean onePhase) throws XAException {
-               try {
-                       checkXid(xid);
-                       WC wc = wc(xid);
-                       if (wc.noModifications())
-                               return;
-                       if (onePhase)
-                               processor.prepare(wc);
-                       processor.commit(wc);
-               } catch (Exception e) {
-                       e.printStackTrace();
-                       throw new XAException(XAException.XAER_RMERR);
-               } finally {
-                       cleanUp(xid);
-               }
-       }
-
-       @Override
-       public void rollback(Xid xid) throws XAException {
-               try {
-                       checkXid(xid);
-                       processor.rollback(wc(xid));
-               } catch (Exception e) {
-                       e.printStackTrace();
-                       throw new XAException(XAException.XAER_RMERR);
-               } finally {
-                       cleanUp(xid);
-               }
-       }
-
-       @Override
-       public void forget(Xid xid) throws XAException {
-               throw new UnsupportedOperationException();
-       }
-
-       @Override
-       public boolean isSameRM(XAResource xares) throws XAException {
-               return xares == this;
-       }
-
-       @Override
-       public Xid[] recover(int flag) throws XAException {
-               return new Xid[0];
-       }
-
-       @Override
-       public int getTransactionTimeout() throws XAException {
-               return transactionTimeout;
-       }
-
-       @Override
-       public boolean setTransactionTimeout(int seconds) throws XAException {
-               transactionTimeout = seconds;
-               return true;
-       }
-
-       private void checkXid(Xid xid) throws XAException {
-               if (xid == null)
-                       throw new XAException(XAException.XAER_OUTSIDE);
-               if (!xid.equals(xid))
-                       throw new XAException(XAException.XAER_NOTA);
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/XAResourceProvider.java b/org.argeo.util/src/org/argeo/util/transaction/XAResourceProvider.java
deleted file mode 100644 (file)
index b0b211b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.argeo.util.transaction;
-
-import javax.transaction.xa.XAResource;
-
-public interface XAResourceProvider {
-       XAResource getXaResource();
-}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/package-info.java b/org.argeo.util/src/org/argeo/util/transaction/package-info.java
deleted file mode 100644 (file)
index f481161..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Minimalistic and partial XA transaction manager implementation. */
-package org.argeo.util.transaction;
\ No newline at end of file
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/.classpath b/osgi/equinox/org.argeo.cms.lib.equinox/.classpath
new file mode 100644 (file)
index 0000000..81fe078
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/.gitignore b/osgi/equinox/org.argeo.cms.lib.equinox/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/.project b/osgi/equinox/org.argeo.cms.lib.equinox/.project
new file mode 100644 (file)
index 0000000..c551d5d
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.cms.lib.equinox</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ds.core.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/META-INF/.gitignore b/osgi/equinox/org.argeo.cms.lib.equinox/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml b/osgi/equinox/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml
new file mode 100644 (file)
index 0000000..6a13362
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" activate="start" deactivate="stop" name="Jetty Service Factory">
+   <implementation class="org.argeo.cms.equinox.http.jetty.EquinoxJettyServer"/>
+   <property name="service.pid" type="String" value="org.argeo.equinox.jetty.config"/>
+   <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
+   <service>
+      <provide interface="com.sun.net.httpserver.HttpServer"/>
+   </service>
+</scr:component>
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/bnd.bnd b/osgi/equinox/org.argeo.cms.lib.equinox/bnd.bnd
new file mode 100644 (file)
index 0000000..2c83158
--- /dev/null
@@ -0,0 +1,2 @@
+Service-Component: \
+OSGI-INF/jettyServiceFactory.xml,\
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/build.properties b/osgi/equinox/org.argeo.cms.lib.equinox/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java
new file mode 100644 (file)
index 0000000..e6595a0
--- /dev/null
@@ -0,0 +1,151 @@
+package org.argeo.cms.equinox.http.jetty;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionIdListener;
+import javax.servlet.http.HttpSessionListener;
+
+import org.argeo.cms.jetty.CmsJettyServer;
+import org.eclipse.equinox.http.servlet.HttpServiceServlet;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.osgi.framework.Constants;
+
+/** A {@link CmsJettyServer} integrating with Equinox HTTP framework. */
+public class EquinoxJettyServer extends CmsJettyServer {
+       private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader";
+
+       @Override
+       protected void addServlets(ServletContextHandler rootContextHandler) throws ServletException {
+               ServletHolder holder = new ServletHolder(new InternalHttpServiceServlet());
+               holder.setInitOrder(0);
+               holder.setInitParameter(Constants.SERVICE_VENDOR, "Eclipse.org"); //$NON-NLS-1$
+               holder.setInitParameter(Constants.SERVICE_DESCRIPTION, "Equinox Jetty-based Http Service"); //$NON-NLS-1$
+
+               rootContextHandler.addServlet(holder, "/*");
+
+               // post-start
+               SessionHandler sessionManager = rootContextHandler.getSessionHandler();
+               sessionManager.addEventListener((HttpSessionIdListener) holder.getServlet());
+       }
+
+       public static class InternalHttpServiceServlet implements HttpSessionListener, HttpSessionIdListener, Servlet {
+               private final Servlet httpServiceServlet = new HttpServiceServlet();
+               private ClassLoader contextLoader;
+               private final Method sessionDestroyed;
+               private final Method sessionIdChanged;
+
+               public InternalHttpServiceServlet() {
+                       Class<?> clazz = httpServiceServlet.getClass();
+
+                       try {
+                               sessionDestroyed = clazz.getMethod("sessionDestroyed", new Class<?>[] { String.class }); //$NON-NLS-1$
+                       } catch (Exception e) {
+                               throw new IllegalStateException(e);
+                       }
+                       try {
+                               sessionIdChanged = clazz.getMethod("sessionIdChanged", new Class<?>[] { String.class }); //$NON-NLS-1$
+                       } catch (Exception e) {
+                               throw new IllegalStateException(e);
+                       }
+               }
+
+               @Override
+               public void init(ServletConfig config) throws ServletException {
+                       ServletContext context = config.getServletContext();
+                       contextLoader = (ClassLoader) context.getAttribute(INTERNAL_CONTEXT_CLASSLOADER);
+
+                       Thread thread = Thread.currentThread();
+                       ClassLoader current = thread.getContextClassLoader();
+                       thread.setContextClassLoader(contextLoader);
+                       try {
+                               httpServiceServlet.init(config);
+                       } finally {
+                               thread.setContextClassLoader(current);
+                       }
+               }
+
+               @Override
+               public void destroy() {
+                       Thread thread = Thread.currentThread();
+                       ClassLoader current = thread.getContextClassLoader();
+                       thread.setContextClassLoader(contextLoader);
+                       try {
+                               httpServiceServlet.destroy();
+                       } finally {
+                               thread.setContextClassLoader(current);
+                       }
+                       contextLoader = null;
+               }
+
+               @Override
+               public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
+                       Thread thread = Thread.currentThread();
+                       ClassLoader current = thread.getContextClassLoader();
+                       thread.setContextClassLoader(contextLoader);
+                       try {
+                               httpServiceServlet.service(req, res);
+                       } finally {
+                               thread.setContextClassLoader(current);
+                       }
+               }
+
+               @Override
+               public ServletConfig getServletConfig() {
+                       return httpServiceServlet.getServletConfig();
+               }
+
+               @Override
+               public String getServletInfo() {
+                       return httpServiceServlet.getServletInfo();
+               }
+
+               @Override
+               public void sessionCreated(HttpSessionEvent event) {
+                       // Nothing to do.
+               }
+
+               @Override
+               public void sessionDestroyed(HttpSessionEvent event) {
+                       Thread thread = Thread.currentThread();
+                       ClassLoader current = thread.getContextClassLoader();
+                       thread.setContextClassLoader(contextLoader);
+                       try {
+                               sessionDestroyed.invoke(httpServiceServlet, event.getSession().getId());
+                       } catch (IllegalAccessException | IllegalArgumentException e) {
+                               // not likely
+                       } catch (InvocationTargetException e) {
+                               throw new RuntimeException(e.getCause());
+                       } finally {
+                               thread.setContextClassLoader(current);
+                       }
+               }
+
+               @Override
+               public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) {
+                       Thread thread = Thread.currentThread();
+                       ClassLoader current = thread.getContextClassLoader();
+                       thread.setContextClassLoader(contextLoader);
+                       try {
+                               sessionIdChanged.invoke(httpServiceServlet, oldSessionId);
+                       } catch (IllegalAccessException | IllegalArgumentException e) {
+                               // not likely
+                       } catch (InvocationTargetException e) {
+                               throw new RuntimeException(e.getCause());
+                       } finally {
+                               thread.setContextClassLoader(current);
+                       }
+               }
+       }
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java
new file mode 100644 (file)
index 0000000..2cd6001
--- /dev/null
@@ -0,0 +1,231 @@
+package org.argeo.cms.servlet.internal.jetty;
+
+import java.io.File;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ForkJoinPool;
+
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsState;
+import org.argeo.cms.CmsDeployProperty;
+import org.argeo.cms.util.LangUtils;
+import org.argeo.cms.websocket.server.CmsWebSocketConfigurator;
+import org.argeo.cms.websocket.server.TestEndpoint;
+import org.eclipse.equinox.http.jetty.JettyConfigurator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class JettyConfig {
+       private final static CmsLog log = CmsLog.getLog(JettyConfig.class);
+
+       final static String CMS_JETTY_CUSTOMIZER_CLASS = "org.argeo.equinox.jetty.CmsJettyCustomizer";
+
+       private CmsState cmsState;
+
+       private final BundleContext bc = FrameworkUtil.getBundle(JettyConfig.class).getBundleContext();
+
+       // private static final String JETTY_PROPERTY_PREFIX =
+       // "org.eclipse.equinox.http.jetty.";
+
+       public void start() {
+               // We need to start asynchronously so that Jetty bundle get started by lazy init
+               // due to the non-configurable behaviour of its activator
+               ForkJoinPool.commonPool().execute(() -> {
+                       Dictionary<String, Object> properties = getHttpServerConfig();
+                       startServer(properties);
+               });
+
+               ServiceTracker<ServerContainer, ServerContainer> serverSt = new ServiceTracker<ServerContainer, ServerContainer>(
+                               bc, ServerContainer.class, null) {
+
+                       @Override
+                       public ServerContainer addingService(ServiceReference<ServerContainer> reference) {
+                               ServerContainer serverContainer = super.addingService(reference);
+
+                               BundleContext bc = reference.getBundle().getBundleContext();
+                               ServiceReference<ServerEndpointConfig.Configurator> srConfigurator = bc
+                                               .getServiceReference(ServerEndpointConfig.Configurator.class);
+                               ServerEndpointConfig.Configurator endpointConfigurator = bc.getService(srConfigurator);
+                               ServerEndpointConfig config = ServerEndpointConfig.Builder
+                                               .create(TestEndpoint.class, "/ws/test/events/").configurator(endpointConfigurator).build();
+                               try {
+                                       serverContainer.addEndpoint(config);
+                               } catch (DeploymentException e) {
+                                       throw new IllegalStateException("Cannot initalise the WebSocket server runtime.", e);
+                               }
+                               return serverContainer;
+                       }
+
+               };
+               serverSt.open();
+
+               // check initialisation
+//             ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
+//
+//                     @Override
+//                     public HttpService addingService(ServiceReference<HttpService> sr) {
+//                             Object httpPort = sr.getProperty("http.port");
+//                             Object httpsPort = sr.getProperty("https.port");
+//                             log.info(httpPortsMsg(httpPort, httpsPort));
+//                             close();
+//                             return super.addingService(sr);
+//                     }
+//             };
+//             httpSt.open();
+       }
+
+       public void stop() {
+               try {
+                       JettyConfigurator.stopServer(CmsConstants.DEFAULT);
+               } catch (Exception e) {
+                       log.error("Cannot stop default Jetty server.", e);
+               }
+
+       }
+
+       public void startServer(Dictionary<String, Object> properties) {
+               // Explicitly configures Jetty so that the default server is not started by the
+               // activator of the Equinox Jetty bundle.
+               Map<String, String> config = LangUtils.dictToStringMap(properties);
+               if (!config.isEmpty()) {
+                       config.put("customizer.class", CMS_JETTY_CUSTOMIZER_CLASS);
+
+                       // TODO centralise with Jetty extender
+                       Object webSocketEnabled = config.get(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty());
+                       if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
+                               bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null);
+                               // config.put(WEBSOCKET_ENABLED, "true");
+                       }
+               }
+
+               properties.put(Constants.SERVICE_PID, "default");
+               File jettyWorkDir = new File(bc.getDataFile(""), "jettywork"); //$NON-NLS-1$
+               jettyWorkDir.mkdir();
+
+//             HttpServerManager serverManager = new HttpServerManager(jettyWorkDir);
+//             try {
+//                     serverManager.updated("default", properties);
+//             } catch (ConfigurationException e) {
+//                     // TODO Auto-generated catch block
+//                     e.printStackTrace();
+//             }
+               Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
+               Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
+               log.info(httpPortsMsg(httpPort, httpsPort));
+
+//             long begin = System.currentTimeMillis();
+//             int tryCount = 60;
+//             try {
+//                     while (tryCount > 0) {
+//                             try {
+//                                     // FIXME deal with multiple ids
+//                                     JettyConfigurator.startServer(CmsConstants.DEFAULT, new Hashtable<>(config));
+//
+//                                     Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
+//                                     Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
+//                                     log.info(httpPortsMsg(httpPort, httpsPort));
+//
+//                                     // Explicitly starts Jetty OSGi HTTP bundle, so that it gets triggered if OSGi
+//                                     // configuration is not cleaned
+//                                     FrameworkUtil.getBundle(JettyConfigurator.class).start();
+//                                     return;
+//                             } catch (IllegalStateException e) {
+//                                     // e.printStackTrace();
+//                                     // Jetty may not be ready
+//                                     try {
+//                                             Thread.sleep(1000);
+//                                     } catch (Exception e1) {
+//                                             // silent
+//                                     }
+//                                     tryCount--;
+//                             }
+//                     }
+//                     long duration = System.currentTimeMillis() - begin;
+//                     log.error("Gave up with starting Jetty server after " + (duration / 1000) + " s");
+//             } catch (Exception e) {
+//                     log.error("Cannot start default Jetty server with config " + properties, e);
+//             }
+
+       }
+
+       private String httpPortsMsg(Object httpPort, Object httpsPort) {
+               return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
+       }
+
+       /** Override the provided config with the framework properties */
+       public Dictionary<String, Object> getHttpServerConfig() {
+               String httpPort = getFrameworkProp(CmsDeployProperty.HTTP_PORT);
+               String httpsPort = getFrameworkProp(CmsDeployProperty.HTTPS_PORT);
+               /// TODO make it more generic
+               String httpHost = getFrameworkProp(CmsDeployProperty.HOST);
+//             String httpsHost = getFrameworkProp(
+//                             JettyConfig.JETTY_PROPERTY_PREFIX + CmsHttpConstants.HTTPS_HOST);
+               String webSocketEnabled = getFrameworkProp(CmsDeployProperty.WEBSOCKET_ENABLED);
+
+               final Hashtable<String, Object> props = new Hashtable<String, Object>();
+               // try {
+               if (httpPort != null || httpsPort != null) {
+                       boolean httpEnabled = httpPort != null;
+                       props.put(JettyHttpConstants.HTTP_ENABLED, httpEnabled);
+                       boolean httpsEnabled = httpsPort != null;
+                       props.put(JettyHttpConstants.HTTPS_ENABLED, httpsEnabled);
+
+                       if (httpEnabled) {
+                               props.put(JettyHttpConstants.HTTP_PORT, httpPort);
+                               if (httpHost != null)
+                                       props.put(JettyHttpConstants.HTTP_HOST, httpHost);
+                       }
+
+                       if (httpsEnabled) {
+                               props.put(JettyHttpConstants.HTTPS_PORT, httpsPort);
+                               if (httpHost != null)
+                                       props.put(JettyHttpConstants.HTTPS_HOST, httpHost);
+
+                               // keystore
+                               props.put(JettyHttpConstants.SSL_KEYSTORETYPE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORETYPE));
+                               props.put(JettyHttpConstants.SSL_KEYSTORE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORE));
+                               props.put(JettyHttpConstants.SSL_PASSWORD, getFrameworkProp(CmsDeployProperty.SSL_PASSWORD));
+
+                               // truststore
+                               props.put(JettyHttpConstants.SSL_TRUSTSTORETYPE,
+                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORETYPE));
+                               props.put(JettyHttpConstants.SSL_TRUSTSTORE, getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORE));
+                               props.put(JettyHttpConstants.SSL_TRUSTSTOREPASSWORD,
+                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
+
+                               // client certificate authentication
+                               String wantClientAuth = getFrameworkProp(CmsDeployProperty.SSL_WANTCLIENTAUTH);
+                               if (wantClientAuth != null)
+                                       props.put(JettyHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
+                               String needClientAuth = getFrameworkProp(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
+                               if (needClientAuth != null)
+                                       props.put(JettyHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
+                       }
+
+                       // web socket
+                       if (webSocketEnabled != null && webSocketEnabled.equals("true"))
+                               props.put(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty(), true);
+
+                       props.put(CmsConstants.CN, CmsConstants.DEFAULT);
+               }
+               return props;
+       }
+
+       private String getFrameworkProp(CmsDeployProperty deployProperty) {
+               return cmsState.getDeployProperty(deployProperty.getProperty());
+       }
+
+       public void setCmsState(CmsState cmsState) {
+               this.cmsState = cmsState;
+       }
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java
new file mode 100644 (file)
index 0000000..8ceb358
--- /dev/null
@@ -0,0 +1,25 @@
+package org.argeo.cms.servlet.internal.jetty;
+
+/** Compatible with Jetty. */
+interface JettyHttpConstants {
+       static final String HTTP_ENABLED = "http.enabled";
+       static final String HTTP_PORT = "http.port";
+       static final String HTTP_HOST = "http.host";
+       static final String HTTPS_ENABLED = "https.enabled";
+       static final String HTTPS_HOST = "https.host";
+       static final String HTTPS_PORT = "https.port";
+       static final String SSL_KEYSTORE = "ssl.keystore";
+       static final String SSL_PASSWORD = "ssl.password";
+       static final String SSL_KEYPASSWORD = "ssl.keypassword";
+       static final String SSL_NEEDCLIENTAUTH = "ssl.needclientauth";
+       static final String SSL_WANTCLIENTAUTH = "ssl.wantclientauth";
+       static final String SSL_PROTOCOL = "ssl.protocol";
+       static final String SSL_ALGORITHM = "ssl.algorithm";
+       static final String SSL_KEYSTORETYPE = "ssl.keystoretype";
+
+       // Argeo
+       static final String SSL_TRUSTSTORE = "ssl.truststore";
+       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
+       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java
new file mode 100644 (file)
index 0000000..7be23fc
--- /dev/null
@@ -0,0 +1,65 @@
+package org.argeo.equinox.jetty;
+
+import java.util.Dictionary;
+
+import javax.servlet.ServletContext;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+
+import org.eclipse.equinox.http.jetty.JettyCustomizer;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/** Customises the Jetty HTTP server. */
+public class CmsJettyCustomizer extends JettyCustomizer {
+       static final String SSL_TRUSTSTORE = "ssl.truststore";
+       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
+       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
+
+       private BundleContext bc = FrameworkUtil.getBundle(CmsJettyCustomizer.class).getBundleContext();
+
+       public final static String WEBSOCKET_ENABLED = "argeo.websocket.enabled";
+
+       @Override
+       public Object customizeContext(Object context, Dictionary<String, ?> settings) {
+               // WebSocket
+               Object webSocketEnabled = settings.get(WEBSOCKET_ENABLED);
+               if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
+                       ServletContextHandler servletContextHandler = (ServletContextHandler) context;
+                       JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
+
+                               @Override
+                               public void accept(ServletContext servletContext, ServerContainer serverContainer)
+                                               throws DeploymentException {
+                                       bc.registerService(javax.websocket.server.ServerContainer.class, serverContainer, null);
+                               }
+                       });
+               }
+               return super.customizeContext(context, settings);
+
+       }
+
+       @Override
+       public Object customizeHttpsConnector(Object connector, Dictionary<String, ?> settings) {
+               ServerConnector httpsConnector = (ServerConnector) connector;
+               if (httpsConnector != null)
+                       for (ConnectionFactory connectionFactory : httpsConnector.getConnectionFactories()) {
+                               if (connectionFactory instanceof SslConnectionFactory) {
+                                       SslContextFactory.Server sslContextFactory = ((SslConnectionFactory) connectionFactory)
+                                                       .getSslContextFactory();
+                                       sslContextFactory.setTrustStorePath((String) settings.get(SSL_TRUSTSTORE));
+                                       sslContextFactory.setTrustStoreType((String) settings.get(SSL_TRUSTSTORETYPE));
+                                       sslContextFactory.setTrustStorePassword((String) settings.get(SSL_TRUSTSTOREPASSWORD));
+                               }
+                       }
+               return super.customizeHttpsConnector(connector, settings);
+       }
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java
new file mode 100644 (file)
index 0000000..41c8ce9
--- /dev/null
@@ -0,0 +1,2 @@
+/** Equinox Jetty extensions. */
+package org.argeo.equinox.jetty;
\ No newline at end of file
index 639ffc61c03f6aebf9cfe5e0f79dd0c4c6aa632a..5bf388711048a659992c292c4b9bdcbc595e066b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 639ffc61c03f6aebf9cfe5e0f79dd0c4c6aa632a
+Subproject commit 5bf388711048a659992c292c4b9bdcbc595e066b
index 4146cb0997d01c890e9879e4121a22c87873886b..98d75162f4672dd8c645221150b1e9ddf0adc691 100644 (file)
@@ -1,4 +1,4 @@
 major=2
 minor=3
-micro=9
+micro=14
 qualifier=.next
\ No newline at end of file
index efae9ba73029929628f10deaba78570ac549d99c..1ca557b7e8de5aa955e94f3f32eb33d6c57fa05d 100644 (file)
@@ -13,11 +13,6 @@ org.argeo.cms.lib.sshd,\
 org.argeo.cms.lib.equinox,\
 org.argeo.cms.lib.jetty,\
 
-argeo.osgi.start.4=\
-org.argeo.cms.jcr
-
-argeo.osgi.start.5.node=\
-org.argeo.cms.e4.rap
 
 # Local
 argeo.node.repo.type=h2
diff --git a/sdk/deploy/.gitignore b/sdk/deploy/.gitignore
new file mode 100644 (file)
index 0000000..08eb0a0
--- /dev/null
@@ -0,0 +1 @@
+!bin/
\ No newline at end of file
diff --git a/sdk/deploy/argeo-cms-rcp/usr/bin/argeo-desktop-open b/sdk/deploy/argeo-cms-rcp/usr/bin/argeo-desktop-open
new file mode 100755 (executable)
index 0000000..17b1e88
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+curl $(cat $XDG_RUNTIME_DIR/argeo.rcp.url)$1
\ No newline at end of file
diff --git a/sdk/deploy/argeo-cms/usr/bin/argeo b/sdk/deploy/argeo-cms/usr/bin/argeo
new file mode 100755 (executable)
index 0000000..636fd47
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+java -Dorg.argeo.api.cli.rootCommand=$0 -jar /usr/share/a2/org.argeo.cms/org.argeo.cms.cli.2.3.jar "$@"
\ No newline at end of file
diff --git a/sdk/deploy/argeo-init/etc/argeo.user.d/jvm.args b/sdk/deploy/argeo-init/etc/argeo.user.d/jvm.args
new file mode 100644 (file)
index 0000000..e69de29
index 8b7f969ec5c825c86c9b94ed1bc5e6fedb785758..2c69636acf74d88856d62a0cd8586594896665aa 100644 (file)
@@ -1,31 +1,42 @@
 [Unit]
 Description=Argeo node %I
-After=network.target
+After=network-online.target
 Wants=postgresql.service
 
 [Service]
 Type=simple
+
+User=daemon
+Group=daemon
+
 StateDirectory=argeo.d/%I
 LogsDirectory=argeo.d/%I
 ConfigurationDirectory=argeo.d/%I
 CacheDirectory=argeo.d/%I
 WorkingDirectory=/var/lib/argeo.d/%I
 
-ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java \
+ExecStart=java \
 -Dosgi.configuration.cascaded=true \
 -Dosgi.sharedConfiguration.area=/etc/argeo.d/%I/ \
 -Dosgi.sharedConfiguration.area.readOnly=true \
--Dosgi.configuration.area=/var/lib/argeo.d/%I/state/ \
--Dosgi.instance.area=/var/lib/argeo.d/%I/data/ \
--Dargeo.node.repo.indexesBase=/var/cache/argeo.d/%I/indexes \
+-Dosgi.configuration.area=${STATE_DIRECTORY}/state/ \
+-Dosgi.instance.area=${STATE_DIRECTORY}/data/ \
+-Dargeo.node.repo.indexesBase=${CACHE_DIRECTORY}/indexes \
 -Declipse.ignoreApp=true \
 -Dosgi.noShutdown=true \
 -Dorg.eclipse.equinox.http.jetty.autostart=false \
 @/etc/argeo.d/jvm.args \
-@/etc/argeo.d/%I/jvm.args \
+@${CONFIGURATION_DIRECTORY}/jvm.args \
 @/usr/share/argeo/jvm.args
+
 # Exit codes of the JVM when SIGTERM or SIGINT have been caught:
 SuccessExitStatus=143 130
 
+CPUAccounting=true
+MemoryAccounting=true
+TasksAccounting=true
+IOAccounting=true
+IPAccounting=true
+
 [Install]
 WantedBy=multi-user.target
diff --git a/sdk/deploy/argeo-init/usr/lib/systemd/user/argeo@.service b/sdk/deploy/argeo-init/usr/lib/systemd/user/argeo@.service
new file mode 100644 (file)
index 0000000..345685a
--- /dev/null
@@ -0,0 +1,30 @@
+[Unit]
+Description=Argeo user node %I
+
+[Service]
+Type=simple
+StateDirectory=argeo.d/%I
+LogsDirectory=argeo.d/%I
+ConfigurationDirectory=argeo.d/%I
+CacheDirectory=argeo.d/%I
+#WorkingDirectory=
+
+ExecStart=java \
+-Dosgi.configuration.cascaded=true \
+-Dosgi.sharedConfiguration.area=/etc/argeo.user.d/%I/ \
+-Dosgi.sharedConfiguration.area.readOnly=true \
+-Dosgi.configuration.area=${STATE_DIRECTORY}/state/ \
+-Dosgi.instance.area=${STATE_DIRECTORY}/data/ \
+-Dargeo.node.repo.indexesBase=${CACHE_DIRECTORY}/indexes \
+-Declipse.ignoreApp=true \
+-Dosgi.noShutdown=true \
+-Dorg.eclipse.equinox.http.jetty.autostart=false \
+-Djava.library.path=/usr/lib/a2/swt/rcp/org.argeo.tp.swt/ \
+@/etc/argeo.user.d/jvm.args \
+@/etc/argeo.user.d/%I/jvm.args \
+@/usr/share/argeo/jvm.args
+# Exit codes of the JVM when SIGTERM or SIGINT have been caught:
+SuccessExitStatus=143 130
+
+[Install]
+WantedBy=multi-user.target
index 105f76962e77eeb53c8bd3d5b1cc93f940c87301..2d3190d6f74b652a301f116f19f21da2b235abce 100644 (file)
@@ -1 +1 @@
--cp /usr/share/a2/osgi/equinox/org.argeo.tp.osgi/org.eclipse.osgi.3.17.jar:/usr/share/a2/org.argeo.cms/org.argeo.init.2.1.jar org.argeo.init.Service
\ No newline at end of file
+-cp /usr/share/a2/osgi/equinox/org.argeo.tp.osgi/org.eclipse.osgi.3.18.jar:/usr/share/a2/org.argeo.cms/org.argeo.init.2.3.jar org.argeo.init.Service
\ No newline at end of file
diff --git a/swt/org.argeo.cms.e4/META-INF/.gitignore b/swt/org.argeo.cms.e4/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/swt/org.argeo.cms.e4/OSGI-INF/homeRepository.xml b/swt/org.argeo.cms.e4/OSGI-INF/homeRepository.xml
deleted file mode 100644 (file)
index 2722aab..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="Home Repository">
-   <implementation class="org.argeo.cms.e4.OsgiFilterContextFunction"/>
-   <property name="service.context.key" type="String" value="(cn=ego)"/>
-   <service>
-      <provide interface="org.eclipse.e4.core.contexts.IContextFunction"/>
-   </service>
-</scr:component>
diff --git a/swt/org.argeo.cms.e4/OSGI-INF/userAdminWrapper.xml b/swt/org.argeo.cms.e4/OSGI-INF/userAdminWrapper.xml
deleted file mode 100644 (file)
index cc7087b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="User Admin Wrapper">
-   <implementation class="org.argeo.cms.e4.users.UserAdminWrapper"/>
-   <reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.util.transaction.WorkTransaction" name="UserTransaction" policy="static"/>
-   <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
-   <service>
-      <provide interface="org.argeo.cms.e4.users.UserAdminWrapper"/>
-   </service>
-   <reference bind="addUserDirectory" cardinality="0..n" interface="org.argeo.osgi.useradmin.UserDirectory" name="UserDirectory" policy="static" unbind="removeUserDirectory"/>
-</scr:component>
index 7cf086181111f366b75ce0d9e844d125a27ec5ef..8839805c1c300d04e18fffad1acd2564eb886900 100644 (file)
@@ -1,19 +1,20 @@
-Service-Component: OSGI-INF/homeRepository.xml,\
-OSGI-INF/userAdminWrapper.xml,\
-OSGI-INF/defaultCallbackHandler.xml
+Service-Component: OSGI-INF/defaultCallbackHandler.xml
 Bundle-ActivationPolicy: lazy
 
 Import-Package: \
 org.argeo.api.acr,\
 org.eclipse.swt,\
 org.eclipse.swt.widgets;version="0.0.0",\
-org.eclipse.e4.ui.model.application.ui,\
-org.eclipse.e4.ui.model.application,\
+org.eclipse.e4.ui.model.application.ui;resolution:=optional,\
+org.eclipse.e4.ui.model.application;resolution:=optional,\
 org.argeo.cms,\
 org.eclipse.core.commands.common,\
 org.eclipse.jface.window,\
 org.eclipse.jface.dialogs,\
 org.argeo.cms.swt.auth,\
+org.argeo.cms.ux.widgets,\
 javax.servlet.*;version="[3,5)",\
+org.eclipse.*;resolution:=optional,\
+javax.*;resolution:=optional,\
 *
 
diff --git a/swt/org.argeo.cms.e4/e4xmi/cms-devops.e4xmi b/swt/org.argeo.cms.e4/e4xmi/cms-devops.e4xmi
deleted file mode 100644 (file)
index f71b83e..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="ASCII"?>
-<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_XqkCQKknEeObFrG_clJBYA" elementId="">
-  <children xsi:type="basic:TrimmedWindow" xmi:id="_Zdy6cKknEeObFrG_clJBYA" elementId="org.argeo.cms.e4.apps.admin.trimmedwindow.0" label="" x="10" y="10" width="500" height="500">
-    <persistedState key="styleOverride" value="8"/>
-    <tags>shellMaximized</tags>
-    <tags>auth.cn=admin,ou=roles,ou=node</tags>
-    <children xsi:type="advanced:PerspectiveStack" xmi:id="_jXVqsCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.perspectivestack.0" selectedElement="_xOVlsDvOEeiF1foPJZSZkw">
-      <children xsi:type="advanced:Perspective" xmi:id="_xOVlsDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.perspective.users" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png">
-        <tags>auth.cn=admin,ou=roles,ou=node</tags>
-        <children xsi:type="basic:PartSashContainer" xmi:id="_1tQoEDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partsashcontainer.2" horizontal="true">
-          <children xsi:type="basic:PartStack" xmi:id="_vtbKkDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.4" containerData="4000" selectedElement="_9gukYDvOEeiF1foPJZSZkw">
-            <children xsi:type="basic:Part" xmi:id="_9gukYDvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.part.users" containerData="" contributionURI="bundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.userssers.UsersView" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person.png">
-              <handlers xmi:id="_0mN68DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.4" contributionUbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.userse4.users.handlers.NewUser" command="_uL5i4DvjEeiF1foPJZSZkw"/>
-              <handlers xmi:id="_ODLdgDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.5" contributbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.userscms.e4.users.handlers.DeleteUsers" command="_xkcMADvjEeiF1foPJZSZkw"/>
-              <toolbar xmi:id="_jLWmkDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.toolbar.1">
-                <children xsi:type="menu:HandledToolItem" xmi:id="_jy_OUDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.new" label="New" iconURI="platform:/plugin/org.argeo.cms.swt/icons/add.png" command="_uL5i4DvjEeiF1foPJZSZkw"/>
-                <children xsi:type="menu:HandledToolItem" xmi:id="_9qszMDvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/delete.png" command="_xkcMADvjEeiF1foPJZSZkw"/>
-              </toolbar>
-            </children>
-          </children>
-          <children xsi:type="basic:PartStack" xmi:id="__g1a8DvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.3" containerData="4000">
-            <tags>usersEditorArea</tags>
-          </children>
-          <children xsi:type="basic:PartStack" xmi:id="_-mFn8DvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partstack.5" containerData="2000">
-            <children xsi:type="basic:Part" xmi:id="_6etk4DvOEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.part.groups" containerData="" contrbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.usersgeo.cms.e4.users.GroupsView" label="Groups" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png">
-              <handlers xmi:id="_cmShoDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.6" cbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.usersg.argeo.cms.e4.users.handlers.NewGroup" command="_uL5i4DvjEeiF1foPJZSZkw"/>
-              <handlers xmi:id="_fbYfcDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.bundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.users4/org.argeo.cms.e4.users.handlers.DeleteGroups" command="_xkcMADvjEeiF1foPJZSZkw"/>
-              <toolbar xmi:id="_Us0rADvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.toolbar.2">
-                <children xsi:type="menu:HandledToolItem" xmi:id="_VQTLgDvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.new" label="New" iconURI="platform:/plugin/org.argeo.cms.swt/icons/add.png" command="_uL5i4DvjEeiF1foPJZSZkw"/>
-                <children xsi:type="menu:HandledToolItem" xmi:id="_XfME8DvkEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/delete.png" command="_xkcMADvjEeiF1foPJZSZkw"/>
-              </toolbar>
-            </children>
-          </children>
-        </children>
-      </children>
-      <children xsi:type="advanced:Perspective" xmi:id="_jvjWYCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.perspective.data" label="Data" iconURI="platform:/plugin/org.argeo.cms.swt/icons/nodes.gif">
-        <children xsi:type="basic:PartSashContainer" xmi:id="_h3tvMCkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partsashcontainer.0" selectedElement="_0B9SECkxEein5vuhpK-Dew" horizontal="true">
-          <children xsi:type="basic:PartStack" xmi:id="_0B9SECkxEein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.0" containerData="4000" selectedElement="_WAjPkCkTEein5vuhpK-Dew">
-            <children xsi:type="basic:Part" xmi:id="_WAjPkCkTEein5vuhpK-Dew" elementId="org.argeo.cms.e4.jcrbrowser" containerData="" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR" iconURI="platform:/plugin/org.argeo.cms.swt/icons/browser.gif">
-              <menus xsi:type="menu:PopupMenu" xmi:id="_eXiUECqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.popupmenu.nodeViewer">
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_GVeO8CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.swt/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_fU238CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_U4o9cCqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.swt/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_Ncxo0CqhEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.remove" label="Remove" iconURI="platform:/plugin/org.argeo.cms.swt/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
-              </menus>
-              <menus xmi:id="_oRg_ACqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.menu.0">
-                <tags>ViewMenu</tags>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_yJR8ECqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.refresh" label="Refresh" iconURI="platform:/plugin/org.argeo.cms.swt/icons/refresh.png" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_o6HQECqTEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.addfoldernode" label="Add folder" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addFolder.gif" command="_RgE5cCqREeidr6NYQH6GbQ"/>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_5D7aACqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.rename" label="Rename" iconURI="platform:/plugin/org.argeo.cms.swt/icons/rename.gif" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_7rR2wCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handledmenuitem.delete" label="Delete" iconURI="platform:/plugin/org.argeo.cms.swt/icons/remove.gif" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
-                <children xsi:type="menu:HandledMenuItem" xmi:id="_XsHLgFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledmenuitem.0" iconURI="platform:/plugin/org.argeo.cms.swt/icons/addRepo.gif" command="_ZWpasFgQEeiknZQLx-vtnA"/>
-              </menus>
-            </children>
-          </children>
-          <children xsi:type="basic:PartStack" xmi:id="_mHrEUCk4Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.partstack.1" containerData="6000">
-            <tags>dataExplorer</tags>
-          </children>
-        </children>
-      </children>
-      <children xsi:type="advanced:Perspective" xmi:id="_u5ZakFhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.perspective.monitoring" label="Monitoring" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif">
-        <children xsi:type="basic:PartStack" xmi:id="_7i7t8FhJEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.partstack.6">
-          <children xsi:type="basic:Part" xmi:id="_KqRZIFhNEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.modules" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.ModulesView" label="Modules" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif"/>
-          <children xsi:type="basic:Part" xmi:id="_dXtIoFhNEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.part.bundles" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.monitoring.BundlesView" label="Bundles" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif"/>
-        </children>
-      </children>
-      <children xsi:type="advanced:Perspective" xmi:id="_ABK2ADsNEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.perspective.files" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif">
-        <children xsi:type="basic:PartSashContainer" xmi:id="_FPimEDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.partsashcontainer.1" horizontal="true">
-          <children xsi:type="basic:PartStack" xmi:id="_H93NgDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.partstack.2" containerData="4000">
-            <children xsi:type="basic:Part" xmi:id="_Izxh0DsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.part.files" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.files.NodeFsBrowserView" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif"/>
-          </children>
-          <children xsi:type="basic:Part" xmi:id="_TMqBMDsSEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.part.0" containerData="6000"/>
-        </children>
-      </children>
-    </children>
-    <handlers xmi:id="_Vwax0DvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handler.8" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.OpenPerspective" command="_AF1UsDvrEeiF1foPJZSZkw"/>
-    <trimBars xmi:id="_euVxMCk2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.trimbar.0" side="Left">
-      <children xsi:type="menu:ToolBar" xmi:id="_fotHsCk2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.toolbar.0">
-        <children xsi:type="menu:HandledToolItem" xmi:id="_jCSQgDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.users" label="Users" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png" command="_AF1UsDvrEeiF1foPJZSZkw">
-          <tags>auth.cn=admin,ou=roles,ou=node</tags>
-          <parameters xmi:id="_lu_uYDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.2" name="perspectiveId" value="org.argeo.cms.e4.perspective.users"/>
-        </children>
-        <children xsi:type="menu:HandledToolItem" xmi:id="_jfUM4Ck2Eein5vuhpK-Dew" elementId="org.argeo.cms.e4.handledtoolitem.test" label="Data" iconURI="platform:/plugin/org.argeo.cms.swt/icons/nodes.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
-          <parameters xmi:id="_KDlXQDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.0" name="perspectiveId" value="org.argeo.cms.e4.perspective.data"/>
-        </children>
-        <children xsi:type="menu:HandledToolItem" xmi:id="_dhv80FhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledtoolitem.monitoring" label="Monitoring" iconURI="platform:/plugin/org.argeo.cms.swt/icons/bundles.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
-          <parameters xmi:id="_kjN0cFhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.parameter.3" name="perspectiveId" value="org.argeo.cms.e4.perspective.monitoring"/>
-        </children>
-        <children xsi:type="menu:HandledToolItem" xmi:id="_b0OHUDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.handledtoolitem.files" label="Files" iconURI="platform:/plugin/org.argeo.cms.swt/icons/file.gif" command="_AF1UsDvrEeiF1foPJZSZkw">
-          <parameters xmi:id="_fXvRYDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.parameter.1" name="perspectiveId" value="org.argeo.cms.e4.perspective.files"/>
-        </children>
-        <children xsi:type="menu:ToolBarSeparator" xmi:id="_wuoL8FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.toolbarseparator.0"/>
-        <children xsi:type="menu:HandledToolItem" xmi:id="_2v8DkFhKEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handledtoolitem.logout" label="Log out" iconURI="platform:/plugin/org.argeo.cms.swt/icons/logout.png" command="_PsWd0FhLEeiknZQLx-vtnA"/>
-      </children>
-    </trimBars>
-  </children>
-  <handlers xmi:id="_Xp-P4CqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.0" contributionURI="bundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.jcr.handlerslers.AddFolderNode" command="_RgE5cCqREeidr6NYQH6GbQ"/>
-  <handlers xmi:id="_jbnNwCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.1" contributionUbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.jcr.handlershandlers.DeleteNodes" command="_ChJ-4CqYEeidr6NYQH6GbQ"/>
-  <handlers xmi:id="_loxB0CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.2" contributbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.jcr.handlersjcr.handlers.Refresh" command="_TOKHsCqYEeidr6NYQH6GbQ"/>
-  <handlers xmi:id="_omPfkCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.handler.3" contrbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.jcr.handlers.e4.jcr.handlers.RenameNode" command="_ZrcUMCqYEeidr6NYQH6GbQ"/>
-  <handlers xmi:id="_dUg-cFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.9" cbundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.jcr.handlers.cms.e4.jcr.handlers.AddRemoteRepository" command="_ZWpasFgQEeiknZQLx-vtnA"/>
-  <handlers xmi:id="_RQyFAFhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.handler.10" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.handlers.CloseWorkbench" command="_PsWd0FhLEeiknZQLx-vtnA"/>
-  <descriptors xmi:id="_XzfoMCqlEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.partdescriptor.nodeEditor" label="Node Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/node.gif" allowMultiple="true" category="dataExplorer" closeable="true" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.jcr.JcrNodeEditor"/>
-  <descriptors xmi:id="_sAdNwDvdEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partdescriptor.userEditor" label="User Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/person.png" allowMultiple="true" category="usersEditorArea" closeable="true" dirtyable=bundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.userscr.e4/org.argeo.cms.e4.users.UserEditor"/>
-  <descriptors xmi:id="_5nK7EDvdEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.partdescriptor.groupEditor" label="Group Editor" iconURI="platform:/plugin/org.argeo.cms.swt/icons/group.png" allowMultiple="true" category="usersEditorArea" closeable="true" dirtyabundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.usersms.jcr.e4/org.argeo.cms.e4.users.GroupEditor"/>
-  <commands xmi:id="_RgE5cCqREeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.addFolderNode" commandName="Add folder node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
-  <commands xmi:id="_ChJ-4CqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.deleteNodes" commandName="Delete nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
-  <commands xmi:id="_TOKHsCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.refreshNodes" commandName="Refresh nodes" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
-  <commands xmi:id="_ZrcUMCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.command.renameNode" commandName="Rename node" category="_MDkwUCqYEeidr6NYQH6GbQ"/>
-  <commands xmi:id="_uL5i4DvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.add" commandName="Add"/>
-  <commands xmi:id="_xkcMADvjEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.delete" commandName="Delete"/>
-  <commands xmi:id="_AF1UsDvrEeiF1foPJZSZkw" elementId="org.argeo.cms.e4.command.openPerspective" commandName="Open Perspective">
-    <parameters xmi:id="_F3WAUDvrEeiF1foPJZSZkw" elementId="perspectiveId" name="Perspective Id" optional="false"/>
-  </commands>
-  <commands xmi:id="_ZWpasFgQEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.addRemoteRepository" commandName="Add Remote Repository"/>
-  <commands xmi:id="_PsWd0FhLEeiknZQLx-vtnA" elementId="org.argeo.cms.e4.command.logout" commandName="Log out"/>
-  <addons xmi:id="_XqkCQaknEeObFrG_clJBYA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
-  <addons xmi:id="_XqkCQqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
-  <addons xmi:id="_XqkCQ6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
-  <addons xmi:id="_XqkCRKknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
-  <addons xmi:id="_XqkCRaknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
-  <addons xmi:id="_XqkCRqknEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
-  <addons xmi:id="_XqkCR6knEeObFrG_clJBYA" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
-  <addons xmi:id="_8VnK8OdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.locale" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.LocaleAddon"/>
-  <addons xmi:id="_-xeJYOdKEeijEOqYKRSeoQ" elementId="org.argeo.cms.e4.addon.auth" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.addons.AuthAddon"/>
-  <categories xmi:id="_MDkwUCqYEeidr6NYQH6GbQ" elementId="org.argeo.cms.e4.category.jcrBrowser" name="JCR Browser"/>
-</application:Application>
index 37f1c0233d27eb7b7ad93974cd2988e53d174ea6..66a5ec8c77089a38c1c92375668dd9bffa0d0cbd 100644 (file)
@@ -8,7 +8,7 @@ import javax.security.auth.Subject;
 import javax.servlet.http.HttpServletRequest;
 
 import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.swt.CmsException;
 import org.eclipse.e4.ui.model.application.MApplication;
 import org.eclipse.e4.ui.model.application.ui.MElementContainer;
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/files/NodeFsBrowserView.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/files/NodeFsBrowserView.java
deleted file mode 100644 (file)
index aabfbf5..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.argeo.cms.e4.files;
-
-import java.net.URI;
-import java.nio.file.FileSystem;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.spi.FileSystemProvider;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-
-import org.argeo.eclipse.ui.fs.SimpleFsBrowser;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-
-/** Browse the node file system. */
-public class NodeFsBrowserView {
-       // public final static String ID = WorkbenchUiPlugin.PLUGIN_ID +
-       // ".nodeFsBrowserView";
-
-       @Inject
-       FileSystemProvider nodeFileSystemProvider;
-
-       @PostConstruct
-       public void createPartControl(Composite parent) {
-               try {
-                       // URI uri = new URI("node://root:demo@localhost:7070/");
-                       URI uri = new URI("node:///");
-                       FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri);
-                       if (fileSystem == null)
-                               fileSystem = nodeFileSystemProvider.newFileSystem(uri, null);
-                       Path nodePath = fileSystem.getPath("/");
-
-                       Path localPath = Paths.get(System.getProperty("user.home"));
-
-                       SimpleFsBrowser browser = new SimpleFsBrowser(parent, SWT.NO_FOCUS);
-                       browser.setInput(nodePath, localPath);
-//                     AdvancedFsBrowser browser = new AdvancedFsBrowser();
-//                     browser.createUi(parent, localPath);
-               } catch (Exception e) {
-                       throw new RuntimeException("Cannot open file system browser", e);
-               }
-       }
-
-       public void setFocus() {
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/files/package-info.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/files/package-info.java
deleted file mode 100644 (file)
index b481dd4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Files browser perspective. */
-package org.argeo.cms.e4.files;
\ No newline at end of file
index 7ef8c59da89dadbcfcc454dde65c482688ad5dec..9624c2d7011b82a7df0ee9df95506f588a11d9ff 100644 (file)
@@ -12,15 +12,14 @@ import javax.inject.Inject;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.security.CryptoKeyring;
-import org.argeo.cms.swt.CmsException;
+import org.argeo.api.cms.keyring.CryptoKeyring;
+import org.argeo.api.cms.transaction.WorkTransaction;
+import org.argeo.cms.CurrentUser;
+import org.argeo.cms.swt.dialogs.CmsFeedback;
 import org.argeo.cms.swt.dialogs.CmsMessageDialog;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.util.transaction.WorkTransaction;
+import org.argeo.cms.ux.widgets.CmsDialog;
 import org.eclipse.e4.core.di.annotations.Execute;
 import org.eclipse.e4.core.di.annotations.Optional;
-import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
@@ -46,7 +45,7 @@ public class ChangePassword {
        @Execute
        public void execute() {
                ChangePasswordDialog dialog = new ChangePasswordDialog(Display.getCurrent().getActiveShell(), userAdmin);
-               if (dialog.open() == Dialog.OK) {
+               if (dialog.open() == CmsDialog.OK) {
                        new CmsMessageDialog(Display.getCurrent().getActiveShell(), passwordChanged.lead(),
                                        CmsMessageDialog.INFORMATION).open();
                }
@@ -58,13 +57,13 @@ public class ChangePassword {
                try {
                        dn = new LdapName(name);
                } catch (InvalidNameException e) {
-                       throw new CmsException("Invalid user dn " + name, e);
+                       throw new IllegalArgumentException("Invalid user dn " + name, e);
                }
                User user = (User) userAdmin.getRole(dn.toString());
                if (!user.hasCredential(null, oldPassword))
-                       throw new CmsException("Invalid password");
+                       throw new IllegalArgumentException("Invalid password");
                if (Arrays.equals(newPassword, new char[0]))
-                       throw new CmsException("New password empty");
+                       throw new IllegalArgumentException("New password empty");
                try {
                        userTransaction.begin();
                        user.getCredentials().put(null, newPassword);
@@ -82,7 +81,7 @@ public class ChangePassword {
                        if (e instanceof RuntimeException)
                                throw (RuntimeException) e;
                        else
-                               throw new CmsException("Cannot change password", e);
+                               throw new IllegalStateException("Cannot change password", e);
                }
        }
 
@@ -116,11 +115,11 @@ public class ChangePassword {
                protected void okPressed() {
                        try {
                                if (!newPassword1.getText().equals(newPassword2.getText()))
-                                       throw new CmsException("New passwords are different");
+                                       throw new IllegalArgumentException("New passwords are different");
                                changePassword(oldPassword.getTextChars(), newPassword1.getTextChars());
-                               closeShell(OK);
+                               closeShell(CmsDialog.OK);
                        } catch (Exception e) {
-                               ErrorFeedback.show("Cannot change password", e);
+                               CmsFeedback.error("Cannot change password", e);
                        }
                }
 
index c2ae4bff7c8b32cb7562c4a28607216276205182..cce18020db355d64681b710f5a526a6b1df9d1f1 100644 (file)
@@ -1,11 +1,9 @@
 package org.argeo.cms.e4.handlers;
 
-import java.security.AccessController;
-
 import javax.security.auth.Subject;
 
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.CurrentUser;
+import org.argeo.cms.util.CurrentSubject;
 import org.eclipse.e4.core.di.annotations.Execute;
 import org.eclipse.e4.ui.workbench.IWorkbench;
 
@@ -17,11 +15,11 @@ public class CloseWorkbench {
        }
 
        protected void logout() {
-               Subject subject = Subject.getSubject(AccessController.getContext());
+               Subject subject = CurrentSubject.current();
                try {
                        CurrentUser.logoutCmsSession(subject);
                } catch (Exception e) {
-                       throw new CmsException("Cannot log out", e);
+                       throw new IllegalStateException("Cannot log out", e);
                }
        }
 
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/BundleNode.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/BundleNode.java
deleted file mode 100644 (file)
index e953683..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.argeo.cms.e4.monitoring;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-
-/** A tree element representing a {@link Bundle} */
-class BundleNode extends TreeParent {
-       private final Bundle bundle;
-
-       public BundleNode(Bundle bundle) {
-               this(bundle, false);
-       }
-
-       @SuppressWarnings("rawtypes")
-       public BundleNode(Bundle bundle, boolean hasChildren) {
-               super(bundle.getSymbolicName());
-               this.bundle = bundle;
-
-               if (hasChildren) {
-                       // REFERENCES
-                       ServiceReference[] usedServices = bundle.getServicesInUse();
-                       if (usedServices != null) {
-                               for (ServiceReference sr : usedServices) {
-                                       if (sr != null)
-                                               addChild(new ServiceReferenceNode(sr, false));
-                               }
-                       }
-
-                       // SERVICES
-                       ServiceReference[] registeredServices = bundle
-                                       .getRegisteredServices();
-                       if (registeredServices != null) {
-                               for (ServiceReference sr : registeredServices) {
-                                       if (sr != null)
-                                               addChild(new ServiceReferenceNode(sr, true));
-                               }
-                       }
-               }
-
-       }
-
-       Bundle getBundle() {
-               return bundle;
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/BundlesView.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/BundlesView.java
deleted file mode 100644 (file)
index c639255..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-//package org.argeo.eclipse.ui.workbench.osgi;
-//public class BundlesView {}
-
-package org.argeo.cms.e4.monitoring;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.eclipse.ui.ColumnViewerComparator;
-import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-/**
- * Overview of the bundles as a table. Equivalent to Equinox 'ss' console
- * command.
- */
-public class BundlesView {
-       private final static BundleContext bc = FrameworkUtil.getBundle(BundlesView.class).getBundleContext();
-       private TableViewer viewer;
-
-       @PostConstruct
-       public void createPartControl(Composite parent) {
-               viewer = new TableViewer(parent);
-               viewer.setContentProvider(new BundleContentProvider());
-               viewer.getTable().setHeaderVisible(true);
-
-               EclipseUiSpecificUtils.enableToolTipSupport(viewer);
-
-               // ID
-               TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(30);
-               column.getColumn().setText("ID");
-               column.getColumn().setAlignment(SWT.RIGHT);
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = -3122136344359358605L;
-
-                       public String getText(Object element) {
-                               return Long.toString(((Bundle) element).getBundleId());
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               // State
-               column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(18);
-               column.getColumn().setText("State");
-               column.setLabelProvider(new StateLabelProvider());
-               new ColumnViewerComparator(column);
-
-               // Symbolic name
-               column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(250);
-               column.getColumn().setText("Symbolic Name");
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = -4280840684440451080L;
-
-                       public String getText(Object element) {
-                               return ((Bundle) element).getSymbolicName();
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               // Version
-               column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(250);
-               column.getColumn().setText("Version");
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = 6871926308708629989L;
-
-                       public String getText(Object element) {
-                               Bundle bundle = (org.osgi.framework.Bundle) element;
-                               return bundle.getVersion().toString();
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               viewer.setInput(bc);
-
-       }
-
-       @Focus
-       public void setFocus() {
-               if (viewer != null)
-                       viewer.getControl().setFocus();
-       }
-
-       /** Content provider managing the array of bundles */
-       private static class BundleContentProvider implements IStructuredContentProvider {
-               private static final long serialVersionUID = -8533792785725875977L;
-
-               public Object[] getElements(Object inputElement) {
-                       if (inputElement instanceof BundleContext) {
-                               BundleContext bc = (BundleContext) inputElement;
-                               return bc.getBundles();
-                       }
-                       return null;
-               }
-
-               public void dispose() {
-               }
-
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               }
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/CmsSessionsView.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/CmsSessionsView.java
deleted file mode 100644 (file)
index 95b1eb2..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-//package org.argeo.eclipse.ui.workbench.osgi;
-//public class BundlesView {}
-
-package org.argeo.cms.e4.monitoring;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.api.cms.CmsSession;
-import org.argeo.cms.auth.RoleNameUtils;
-import org.argeo.eclipse.ui.ColumnViewerComparator;
-import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
-import org.argeo.util.LangUtils;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-/**
- * Overview of the active CMS sessions.
- */
-public class CmsSessionsView {
-       private final static BundleContext bc = FrameworkUtil.getBundle(CmsSessionsView.class).getBundleContext();
-
-       private TableViewer viewer;
-
-       @PostConstruct
-       public void createPartControl(Composite parent) {
-               viewer = new TableViewer(parent);
-               viewer.setContentProvider(new CmsSessionContentProvider());
-               viewer.getTable().setHeaderVisible(true);
-
-               EclipseUiSpecificUtils.enableToolTipSupport(viewer);
-
-               int longColWidth = 150;
-               int smallColWidth = 100;
-
-               // Display name
-               TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(longColWidth);
-               column.getColumn().setText("User");
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = -5234573509093747505L;
-
-                       public String getText(Object element) {
-                               return ((CmsSession) element).getDisplayName();
-                       }
-
-                       public String getToolTipText(Object element) {
-                               return ((CmsSession) element).getUserDn().toString();
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               // Creation time
-               column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(smallColWidth);
-               column.getColumn().setText("Since");
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = -5234573509093747505L;
-
-                       public String getText(Object element) {
-                               return LangUtils.since(((CmsSession) element).getCreationTime());
-                       }
-
-                       public String getToolTipText(Object element) {
-                               return ((CmsSession) element).getCreationTime().toString();
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               // Username
-               column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(smallColWidth);
-               column.getColumn().setText("Username");
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = -5234573509093747505L;
-
-                       public String getText(Object element) {
-                               String userDn = ((CmsSession) element).getUserDn();
-                               return RoleNameUtils.getLastRdnValue(userDn);
-                       }
-
-                       public String getToolTipText(Object element) {
-                               return ((CmsSession) element).getUserDn().toString();
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               // UUID
-               column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(smallColWidth);
-               column.getColumn().setText("UUID");
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = -5234573509093747505L;
-
-                       public String getText(Object element) {
-                               return ((CmsSession) element).getUuid().toString();
-                       }
-
-                       public String getToolTipText(Object element) {
-                               return getText(element);
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               // Local ID
-               column = new TableViewerColumn(viewer, SWT.NONE);
-               column.getColumn().setWidth(smallColWidth);
-               column.getColumn().setText("Local ID");
-               column.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = -5234573509093747505L;
-
-                       public String getText(Object element) {
-                               return ((CmsSession) element).getLocalId();
-                       }
-
-                       public String getToolTipText(Object element) {
-                               return getText(element);
-                       }
-               });
-               new ColumnViewerComparator(column);
-
-               viewer.setInput(bc);
-
-       }
-
-       @Focus
-       public void setFocus() {
-               if (viewer != null)
-                       viewer.getControl().setFocus();
-       }
-
-       /** Content provider managing the array of bundles */
-       private static class CmsSessionContentProvider implements IStructuredContentProvider {
-               private static final long serialVersionUID = -8533792785725875977L;
-
-               public Object[] getElements(Object inputElement) {
-                       if (inputElement instanceof BundleContext) {
-                               BundleContext bc = (BundleContext) inputElement;
-                               Collection<ServiceReference<CmsSession>> srs;
-                               try {
-                                       srs = bc.getServiceReferences(CmsSession.class, null);
-                               } catch (InvalidSyntaxException e) {
-                                       throw new IllegalArgumentException("Cannot retrieve CMS sessions", e);
-                               }
-                               List<CmsSession> res = new ArrayList<>();
-                               for (ServiceReference<CmsSession> sr : srs) {
-                                       res.add(bc.getService(sr));
-                               }
-                               return res.toArray();
-                       }
-                       return null;
-               }
-
-               public void dispose() {
-               }
-
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               }
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/ModulesView.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/ModulesView.java
deleted file mode 100644 (file)
index 6317882..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.argeo.cms.e4.monitoring;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-/** The OSGi runtime from a module perspective. */
-public class ModulesView {
-       private final static BundleContext bc = FrameworkUtil.getBundle(ModulesView.class).getBundleContext();
-       private TreeViewer viewer;
-
-       @PostConstruct
-       public void createPartControl(Composite parent) {
-               viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
-               viewer.setContentProvider(new ModulesContentProvider());
-               viewer.setLabelProvider(new ModulesLabelProvider());
-               viewer.setInput(bc);
-       }
-
-       @Focus
-       public void setFocus() {
-               viewer.getTree().setFocus();
-       }
-
-       private class ModulesContentProvider implements ITreeContentProvider {
-               private static final long serialVersionUID = 3819934804640641721L;
-
-               public Object[] getElements(Object inputElement) {
-                       return getChildren(inputElement);
-               }
-
-               public Object[] getChildren(Object parentElement) {
-                       if (parentElement instanceof BundleContext) {
-                               BundleContext bundleContext = (BundleContext) parentElement;
-                               Bundle[] bundles = bundleContext.getBundles();
-
-                               List<BundleNode> modules = new ArrayList<BundleNode>();
-                               for (Bundle bundle : bundles) {
-                                       if (bundle.getState() == Bundle.ACTIVE)
-                                               modules.add(new BundleNode(bundle, true));
-                               }
-                               return modules.toArray();
-                       } else if (parentElement instanceof TreeParent) {
-                               return ((TreeParent) parentElement).getChildren();
-                       } else {
-                               return null;
-                       }
-               }
-
-               public Object getParent(Object element) {
-                       // TODO Auto-generated method stub
-                       return null;
-               }
-
-               public boolean hasChildren(Object element) {
-                       if (element instanceof TreeParent) {
-                               return ((TreeParent) element).hasChildren();
-                       }
-                       return false;
-               }
-
-               public void dispose() {
-               }
-
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               }
-       }
-
-       private class ModulesLabelProvider extends StateLabelProvider {
-               private static final long serialVersionUID = 5290046145534824722L;
-
-               @Override
-               public String getText(Object element) {
-                       if (element instanceof BundleNode)
-                               return element.toString() + " [" + ((BundleNode) element).getBundle().getBundleId() + "]";
-                       return element.toString();
-               }
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/OsgiConfigurationsView.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/OsgiConfigurationsView.java
deleted file mode 100644 (file)
index 5db8bd1..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-package org.argeo.cms.e4.monitoring;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Dictionary;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.cms.swt.CmsException;
-import org.argeo.util.LangUtils;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-
-public class OsgiConfigurationsView {
-       private final static BundleContext bc = FrameworkUtil.getBundle(OsgiConfigurationsView.class).getBundleContext();
-
-       @PostConstruct
-       public void createPartControl(Composite parent) {
-               ConfigurationAdmin configurationAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class));
-
-               TreeViewer viewer = new TreeViewer(parent);
-               // viewer.getTree().setHeaderVisible(true);
-
-               TreeViewerColumn tvc = new TreeViewerColumn(viewer, SWT.NONE);
-               tvc.getColumn().setWidth(400);
-               tvc.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = 835407996597566763L;
-
-                       @Override
-                       public String getText(Object element) {
-                               if (element instanceof Configuration) {
-                                       return ((Configuration) element).getPid();
-                               } else if (element instanceof Prop) {
-                                       return ((Prop) element).key;
-                               }
-                               return super.getText(element);
-                       }
-
-                       @Override
-                       public Image getImage(Object element) {
-                               if (element instanceof Configuration)
-                                       return OsgiExplorerImages.CONFIGURATION;
-                               return null;
-                       }
-
-               });
-
-               tvc = new TreeViewerColumn(viewer, SWT.NONE);
-               tvc.getColumn().setWidth(400);
-               tvc.setLabelProvider(new ColumnLabelProvider() {
-                       private static final long serialVersionUID = 6999659261190014687L;
-
-                       @Override
-                       public String getText(Object element) {
-                               if (element instanceof Configuration) {
-                                       // return ((Configuration) element).getFactoryPid();
-                                       return null;
-                               } else if (element instanceof Prop) {
-                                       return ((Prop) element).value.toString();
-                               }
-                               return super.getText(element);
-                       }
-               });
-
-               viewer.setContentProvider(new ConfigurationsContentProvider());
-               viewer.setInput(configurationAdmin);
-       }
-
-       static class ConfigurationsContentProvider implements ITreeContentProvider {
-               private static final long serialVersionUID = -4892768279440981042L;
-               private ConfigurationComparator configurationComparator = new ConfigurationComparator();
-
-               @Override
-               public void dispose() {
-               }
-
-               @Override
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               }
-
-               @Override
-               public Object[] getElements(Object inputElement) {
-                       ConfigurationAdmin configurationAdmin = (ConfigurationAdmin) inputElement;
-                       try {
-                               Configuration[] configurations = configurationAdmin.listConfigurations(null);
-                               Arrays.sort(configurations, configurationComparator);
-                               return configurations;
-                       } catch (IOException | InvalidSyntaxException e) {
-                               throw new CmsException("Cannot list configurations", e);
-                       }
-               }
-
-               @Override
-               public Object[] getChildren(Object parentElement) {
-                       if (parentElement instanceof Configuration) {
-                               List<Prop> res = new ArrayList<>();
-                               Configuration configuration = (Configuration) parentElement;
-                               Dictionary<String, Object> props = configuration.getProperties();
-                               keys: for (String key : LangUtils.keys(props)) {
-                                       if (Constants.SERVICE_PID.equals(key))
-                                               continue keys;
-                                       if (ConfigurationAdmin.SERVICE_FACTORYPID.equals(key))
-                                               continue keys;
-                                       res.add(new Prop(configuration, key, props.get(key)));
-                               }
-                               return res.toArray(new Prop[res.size()]);
-                       }
-                       return null;
-               }
-
-               @Override
-               public Object getParent(Object element) {
-                       if (element instanceof Prop)
-                               return ((Prop) element).configuration;
-                       return null;
-               }
-
-               @Override
-               public boolean hasChildren(Object element) {
-                       if (element instanceof Configuration)
-                               return true;
-                       return false;
-               }
-
-       }
-
-       static class Prop {
-               final Configuration configuration;
-               final String key;
-               final Object value;
-
-               public Prop(Configuration configuration, String key, Object value) {
-                       this.configuration = configuration;
-                       this.key = key;
-                       this.value = value;
-               }
-
-       }
-
-       static class ConfigurationComparator implements Comparator<Configuration> {
-
-               @Override
-               public int compare(Configuration o1, Configuration o2) {
-                       return o1.getPid().compareTo(o2.getPid());
-               }
-
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/OsgiExplorerImages.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/OsgiExplorerImages.java
deleted file mode 100644 (file)
index 7217fe6..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.cms.e4.monitoring;
-
-import org.argeo.cms.ui.theme.CmsImages;
-import org.eclipse.swt.graphics.Image;
-
-/** Shared icons. */
-public class OsgiExplorerImages extends CmsImages {
-       public final static Image INSTALLED = createIcon("installed.gif");
-       public final static Image RESOLVED = createIcon("resolved.gif");
-       public final static Image STARTING = createIcon("starting.gif");
-       public final static Image ACTIVE = createIcon("active.gif");
-       public final static Image SERVICE_PUBLISHED = createIcon("service_published.gif");
-       public final static Image SERVICE_REFERENCED = createIcon("service_referenced.gif");
-       public final static Image CONFIGURATION = createIcon("node.gif");
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/ServiceReferenceNode.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/ServiceReferenceNode.java
deleted file mode 100644 (file)
index 1c60811..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.argeo.cms.e4.monitoring;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-
-/** A tree element representing a {@link ServiceReference} */
-@SuppressWarnings({ "rawtypes" })
-class ServiceReferenceNode extends TreeParent {
-       private final ServiceReference serviceReference;
-       private final boolean published;
-
-       public ServiceReferenceNode(ServiceReference serviceReference,
-                       boolean published) {
-               super(serviceReference.toString());
-               this.serviceReference = serviceReference;
-               this.published = published;
-
-               if (isPublished()) {
-                       Bundle[] usedBundles = serviceReference.getUsingBundles();
-                       if (usedBundles != null) {
-                               for (Bundle b : usedBundles) {
-                                       if (b != null)
-                                               addChild(new BundleNode(b));
-                               }
-                       }
-               } else {
-                       Bundle provider = serviceReference.getBundle();
-                       addChild(new BundleNode(provider));
-               }
-
-               for (String key : serviceReference.getPropertyKeys()) {
-                       addChild(new TreeParent(key + "="
-                                       + serviceReference.getProperty(key)));
-               }
-
-       }
-
-       public ServiceReference getServiceReference() {
-               return serviceReference;
-       }
-
-       public boolean isPublished() {
-               return published;
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/StateLabelProvider.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/StateLabelProvider.java
deleted file mode 100644 (file)
index 5cb5b65..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.argeo.cms.e4.monitoring;
-
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Image;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-
-/** Label provider showing the sate of bundles */
-class StateLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = -7885583135316000733L;
-
-       @Override
-       public Image getImage(Object element) {
-               int state;
-               if (element instanceof Bundle)
-                       state = ((Bundle) element).getState();
-               else if (element instanceof BundleNode)
-                       state = ((BundleNode) element).getBundle().getState();
-               else if (element instanceof ServiceReferenceNode)
-                       if (((ServiceReferenceNode) element).isPublished())
-                               return OsgiExplorerImages.SERVICE_PUBLISHED;
-                       else
-                               return OsgiExplorerImages.SERVICE_REFERENCED;
-               else
-                       return null;
-
-               switch (state) {
-               case Bundle.UNINSTALLED:
-                       return OsgiExplorerImages.INSTALLED;
-               case Bundle.INSTALLED:
-                       return OsgiExplorerImages.INSTALLED;
-               case Bundle.RESOLVED:
-                       return OsgiExplorerImages.RESOLVED;
-               case Bundle.STARTING:
-                       return OsgiExplorerImages.STARTING;
-               case Bundle.STOPPING:
-                       return OsgiExplorerImages.STARTING;
-               case Bundle.ACTIVE:
-                       return OsgiExplorerImages.ACTIVE;
-               default:
-                       return null;
-               }
-       }
-
-       @Override
-       public String getText(Object element) {
-               return null;
-       }
-
-       @Override
-       public String getToolTipText(Object element) {
-               Bundle bundle = (Bundle) element;
-               Integer state = bundle.getState();
-               switch (state) {
-               case Bundle.UNINSTALLED:
-                       return "UNINSTALLED";
-               case Bundle.INSTALLED:
-                       return "INSTALLED";
-               case Bundle.RESOLVED:
-                       return "RESOLVED";
-               case Bundle.STARTING:
-                       String activationPolicy = bundle.getHeaders()
-                                       .get(Constants.BUNDLE_ACTIVATIONPOLICY).toString();
-
-                       // .get("Bundle-ActivationPolicy").toString();
-                       // FIXME constant triggers the compilation failure
-                       if (activationPolicy != null
-                                       && activationPolicy.equals(Constants.ACTIVATION_LAZY))
-                               // && activationPolicy.equals("lazy"))
-                               // FIXME constant triggers the compilation failure
-                               // && activationPolicy.equals(Constants.ACTIVATION_LAZY))
-                               return "<<LAZY>>";
-                       return "STARTING";
-               case Bundle.STOPPING:
-                       return "STOPPING";
-               case Bundle.ACTIVE:
-                       return "ACTIVE";
-               default:
-                       return null;
-               }
-       }
-}
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/package-info.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/monitoring/package-info.java
deleted file mode 100644 (file)
index 873bf31..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Monitoring perspective. */
-package org.argeo.cms.e4.monitoring;
\ No newline at end of file
diff --git a/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/EgoDashboard.java b/swt/org.argeo.cms.e4/src/org/argeo/cms/e4/parts/EgoDashboard.java
deleted file mode 100644 (file)
index f2a73f2..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.argeo.cms.e4.parts;
-
-import java.time.ZonedDateTime;
-
-import javax.annotation.PostConstruct;
-
-import org.argeo.api.cms.CmsSession;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** A canonical view of the logged in user. */
-public class EgoDashboard {
-//     private BundleContext bc = FrameworkUtil.getBundle(EgoDashboard.class).getBundleContext();
-
-       @PostConstruct
-       public void createPartControl(Composite p) {
-               p.setLayout(new GridLayout());
-               String username = CurrentUser.getUsername();
-
-               CmsSwtUtils.lbl(p, "<strong>" + CurrentUser.getDisplayName() + "</strong>");
-               CmsSwtUtils.txt(p, username);
-               CmsSwtUtils.lbl(p, "Roles:");
-               roles: for (String role : CurrentUser.roles()) {
-                       if (username.equals(role))
-                               continue roles;
-                       CmsSwtUtils.txt(p, role);
-               }
-
-//             Subject subject = Subject.getSubject(AccessController.getContext());
-//             if (subject != null) {
-               CmsSession cmsSession = CurrentUser.getCmsSession();
-               ZonedDateTime loggedIndSince = cmsSession.getCreationTime();
-               CmsSwtUtils.lbl(p, "Session:");
-               CmsSwtUtils.txt(p, cmsSession.getUuid().toString());
-               CmsSwtUtils.lbl(p, "Logged in since:");
-               CmsSwtUtils.txt(p, loggedIndSince.toString());
-//             }
-       }
-}
index 2dda08b2ab14788163a859298653d99f8e4e226d..1dfa6599dd52e926dcf8678dd3beb8f4261a9c48 100644 (file)
@@ -1,5 +1,6 @@
 Import-Package: org.eclipse.swt,\
 org.eclipse.jface.window,\
+org.eclipse.jface.dialogs,\
 org.eclipse.core.commands.common,\
 javax.servlet.*;version="[3,5)",\
 *
diff --git a/swt/org.argeo.cms.swt/icons/actions/add.png b/swt/org.argeo.cms.swt/icons/actions/add.png
deleted file mode 100644 (file)
index 5c06bf0..0000000
Binary files a/swt/org.argeo.cms.swt/icons/actions/add.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/actions/close-all.png b/swt/org.argeo.cms.swt/icons/actions/close-all.png
deleted file mode 100644 (file)
index 81bfc95..0000000
Binary files a/swt/org.argeo.cms.swt/icons/actions/close-all.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/actions/delete.png b/swt/org.argeo.cms.swt/icons/actions/delete.png
deleted file mode 100644 (file)
index 9712723..0000000
Binary files a/swt/org.argeo.cms.swt/icons/actions/delete.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/actions/edit.png b/swt/org.argeo.cms.swt/icons/actions/edit.png
deleted file mode 100644 (file)
index ad3db9f..0000000
Binary files a/swt/org.argeo.cms.swt/icons/actions/edit.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/actions/save-all.png b/swt/org.argeo.cms.swt/icons/actions/save-all.png
deleted file mode 100644 (file)
index f48ed32..0000000
Binary files a/swt/org.argeo.cms.swt/icons/actions/save-all.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/actions/save.png b/swt/org.argeo.cms.swt/icons/actions/save.png
deleted file mode 100644 (file)
index 1c58ada..0000000
Binary files a/swt/org.argeo.cms.swt/icons/actions/save.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/active.gif b/swt/org.argeo.cms.swt/icons/active.gif
deleted file mode 100644 (file)
index 7d24707..0000000
Binary files a/swt/org.argeo.cms.swt/icons/active.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/add.gif b/swt/org.argeo.cms.swt/icons/add.gif
deleted file mode 100644 (file)
index 252d7eb..0000000
Binary files a/swt/org.argeo.cms.swt/icons/add.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/add.png b/swt/org.argeo.cms.swt/icons/add.png
deleted file mode 100644 (file)
index c7edfec..0000000
Binary files a/swt/org.argeo.cms.swt/icons/add.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/addFolder.gif b/swt/org.argeo.cms.swt/icons/addFolder.gif
deleted file mode 100644 (file)
index d3f43d9..0000000
Binary files a/swt/org.argeo.cms.swt/icons/addFolder.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/addPrivileges.gif b/swt/org.argeo.cms.swt/icons/addPrivileges.gif
deleted file mode 100644 (file)
index a6b251f..0000000
Binary files a/swt/org.argeo.cms.swt/icons/addPrivileges.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/addRepo.gif b/swt/org.argeo.cms.swt/icons/addRepo.gif
deleted file mode 100644 (file)
index 26d81c0..0000000
Binary files a/swt/org.argeo.cms.swt/icons/addRepo.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/addWorkspace.png b/swt/org.argeo.cms.swt/icons/addWorkspace.png
deleted file mode 100644 (file)
index bbee775..0000000
Binary files a/swt/org.argeo.cms.swt/icons/addWorkspace.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/adminLog.gif b/swt/org.argeo.cms.swt/icons/adminLog.gif
deleted file mode 100644 (file)
index 6ef3bca..0000000
Binary files a/swt/org.argeo.cms.swt/icons/adminLog.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/batch.gif b/swt/org.argeo.cms.swt/icons/batch.gif
deleted file mode 100644 (file)
index b8ca14a..0000000
Binary files a/swt/org.argeo.cms.swt/icons/batch.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/begin.gif b/swt/org.argeo.cms.swt/icons/begin.gif
deleted file mode 100755 (executable)
index feb8e94..0000000
Binary files a/swt/org.argeo.cms.swt/icons/begin.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/binary.png b/swt/org.argeo.cms.swt/icons/binary.png
deleted file mode 100644 (file)
index fdf4f82..0000000
Binary files a/swt/org.argeo.cms.swt/icons/binary.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/browser.gif b/swt/org.argeo.cms.swt/icons/browser.gif
deleted file mode 100644 (file)
index 6c7320c..0000000
Binary files a/swt/org.argeo.cms.swt/icons/browser.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/bundles.gif b/swt/org.argeo.cms.swt/icons/bundles.gif
deleted file mode 100644 (file)
index e9a6bd9..0000000
Binary files a/swt/org.argeo.cms.swt/icons/bundles.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/changePassword.gif b/swt/org.argeo.cms.swt/icons/changePassword.gif
deleted file mode 100644 (file)
index 274a850..0000000
Binary files a/swt/org.argeo.cms.swt/icons/changePassword.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/clear.gif b/swt/org.argeo.cms.swt/icons/clear.gif
deleted file mode 100644 (file)
index 6bc10f9..0000000
Binary files a/swt/org.argeo.cms.swt/icons/clear.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/close-all.png b/swt/org.argeo.cms.swt/icons/close-all.png
deleted file mode 100644 (file)
index 85d4d42..0000000
Binary files a/swt/org.argeo.cms.swt/icons/close-all.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/commit.gif b/swt/org.argeo.cms.swt/icons/commit.gif
deleted file mode 100755 (executable)
index 876f3eb..0000000
Binary files a/swt/org.argeo.cms.swt/icons/commit.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/delete.png b/swt/org.argeo.cms.swt/icons/delete.png
deleted file mode 100644 (file)
index 676a39d..0000000
Binary files a/swt/org.argeo.cms.swt/icons/delete.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/dumpNode.gif b/swt/org.argeo.cms.swt/icons/dumpNode.gif
deleted file mode 100644 (file)
index 14eb1be..0000000
Binary files a/swt/org.argeo.cms.swt/icons/dumpNode.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/file.gif b/swt/org.argeo.cms.swt/icons/file.gif
deleted file mode 100644 (file)
index ef30288..0000000
Binary files a/swt/org.argeo.cms.swt/icons/file.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/folder.gif b/swt/org.argeo.cms.swt/icons/folder.gif
deleted file mode 100644 (file)
index 42e027c..0000000
Binary files a/swt/org.argeo.cms.swt/icons/folder.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/getSize.gif b/swt/org.argeo.cms.swt/icons/getSize.gif
deleted file mode 100644 (file)
index b05bf3e..0000000
Binary files a/swt/org.argeo.cms.swt/icons/getSize.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/group.png b/swt/org.argeo.cms.swt/icons/group.png
deleted file mode 100644 (file)
index cc6683a..0000000
Binary files a/swt/org.argeo.cms.swt/icons/group.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/home.gif b/swt/org.argeo.cms.swt/icons/home.gif
deleted file mode 100644 (file)
index fd0c669..0000000
Binary files a/swt/org.argeo.cms.swt/icons/home.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/home.png b/swt/org.argeo.cms.swt/icons/home.png
deleted file mode 100644 (file)
index 5eb0967..0000000
Binary files a/swt/org.argeo.cms.swt/icons/home.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/import_fs.png b/swt/org.argeo.cms.swt/icons/import_fs.png
deleted file mode 100644 (file)
index d7c890c..0000000
Binary files a/swt/org.argeo.cms.swt/icons/import_fs.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/installed.gif b/swt/org.argeo.cms.swt/icons/installed.gif
deleted file mode 100644 (file)
index 2988716..0000000
Binary files a/swt/org.argeo.cms.swt/icons/installed.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/log.gif b/swt/org.argeo.cms.swt/icons/log.gif
deleted file mode 100644 (file)
index e3ecc55..0000000
Binary files a/swt/org.argeo.cms.swt/icons/log.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/logout.png b/swt/org.argeo.cms.swt/icons/logout.png
deleted file mode 100644 (file)
index f2952fa..0000000
Binary files a/swt/org.argeo.cms.swt/icons/logout.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/maintenance.gif b/swt/org.argeo.cms.swt/icons/maintenance.gif
deleted file mode 100644 (file)
index e5690ec..0000000
Binary files a/swt/org.argeo.cms.swt/icons/maintenance.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/node.gif b/swt/org.argeo.cms.swt/icons/node.gif
deleted file mode 100644 (file)
index 364c0e7..0000000
Binary files a/swt/org.argeo.cms.swt/icons/node.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/nodes.gif b/swt/org.argeo.cms.swt/icons/nodes.gif
deleted file mode 100644 (file)
index bba3dbc..0000000
Binary files a/swt/org.argeo.cms.swt/icons/nodes.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/osgi_explorer.gif b/swt/org.argeo.cms.swt/icons/osgi_explorer.gif
deleted file mode 100644 (file)
index e9a6bd9..0000000
Binary files a/swt/org.argeo.cms.swt/icons/osgi_explorer.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/password.gif b/swt/org.argeo.cms.swt/icons/password.gif
deleted file mode 100644 (file)
index a6b251f..0000000
Binary files a/swt/org.argeo.cms.swt/icons/password.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/person-logged-in.png b/swt/org.argeo.cms.swt/icons/person-logged-in.png
deleted file mode 100644 (file)
index 87acc14..0000000
Binary files a/swt/org.argeo.cms.swt/icons/person-logged-in.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/person.png b/swt/org.argeo.cms.swt/icons/person.png
deleted file mode 100644 (file)
index 7d979a5..0000000
Binary files a/swt/org.argeo.cms.swt/icons/person.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/query.png b/swt/org.argeo.cms.swt/icons/query.png
deleted file mode 100644 (file)
index 54c089d..0000000
Binary files a/swt/org.argeo.cms.swt/icons/query.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/refresh.png b/swt/org.argeo.cms.swt/icons/refresh.png
deleted file mode 100644 (file)
index 71b3481..0000000
Binary files a/swt/org.argeo.cms.swt/icons/refresh.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/remote_connected.gif b/swt/org.argeo.cms.swt/icons/remote_connected.gif
deleted file mode 100644 (file)
index 1492b4e..0000000
Binary files a/swt/org.argeo.cms.swt/icons/remote_connected.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/remote_disconnected.gif b/swt/org.argeo.cms.swt/icons/remote_disconnected.gif
deleted file mode 100644 (file)
index 6c54da9..0000000
Binary files a/swt/org.argeo.cms.swt/icons/remote_disconnected.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/remove.gif b/swt/org.argeo.cms.swt/icons/remove.gif
deleted file mode 100644 (file)
index 0ae6dec..0000000
Binary files a/swt/org.argeo.cms.swt/icons/remove.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/removePrivileges.gif b/swt/org.argeo.cms.swt/icons/removePrivileges.gif
deleted file mode 100644 (file)
index aa78fd2..0000000
Binary files a/swt/org.argeo.cms.swt/icons/removePrivileges.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/rename.gif b/swt/org.argeo.cms.swt/icons/rename.gif
deleted file mode 100644 (file)
index 8048405..0000000
Binary files a/swt/org.argeo.cms.swt/icons/rename.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/repositories.gif b/swt/org.argeo.cms.swt/icons/repositories.gif
deleted file mode 100644 (file)
index c13bea1..0000000
Binary files a/swt/org.argeo.cms.swt/icons/repositories.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/repository_connected.gif b/swt/org.argeo.cms.swt/icons/repository_connected.gif
deleted file mode 100644 (file)
index a15fa55..0000000
Binary files a/swt/org.argeo.cms.swt/icons/repository_connected.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/repository_disconnected.gif b/swt/org.argeo.cms.swt/icons/repository_disconnected.gif
deleted file mode 100644 (file)
index 4576dc5..0000000
Binary files a/swt/org.argeo.cms.swt/icons/repository_disconnected.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/resolved.gif b/swt/org.argeo.cms.swt/icons/resolved.gif
deleted file mode 100644 (file)
index f4a1ea1..0000000
Binary files a/swt/org.argeo.cms.swt/icons/resolved.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/role.gif b/swt/org.argeo.cms.swt/icons/role.gif
deleted file mode 100644 (file)
index 274a850..0000000
Binary files a/swt/org.argeo.cms.swt/icons/role.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/rollback.gif b/swt/org.argeo.cms.swt/icons/rollback.gif
deleted file mode 100755 (executable)
index c753995..0000000
Binary files a/swt/org.argeo.cms.swt/icons/rollback.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/save-all.png b/swt/org.argeo.cms.swt/icons/save-all.png
deleted file mode 100644 (file)
index b68a29b..0000000
Binary files a/swt/org.argeo.cms.swt/icons/save-all.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/save.gif b/swt/org.argeo.cms.swt/icons/save.gif
deleted file mode 100644 (file)
index 654ad7b..0000000
Binary files a/swt/org.argeo.cms.swt/icons/save.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/save.png b/swt/org.argeo.cms.swt/icons/save.png
deleted file mode 100644 (file)
index f27ef2d..0000000
Binary files a/swt/org.argeo.cms.swt/icons/save.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/save_security.png b/swt/org.argeo.cms.swt/icons/save_security.png
deleted file mode 100644 (file)
index ca41dc9..0000000
Binary files a/swt/org.argeo.cms.swt/icons/save_security.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/save_security_disabled.png b/swt/org.argeo.cms.swt/icons/save_security_disabled.png
deleted file mode 100644 (file)
index fb7d08d..0000000
Binary files a/swt/org.argeo.cms.swt/icons/save_security_disabled.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/security.gif b/swt/org.argeo.cms.swt/icons/security.gif
deleted file mode 100644 (file)
index 57fb95e..0000000
Binary files a/swt/org.argeo.cms.swt/icons/security.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/service_published.gif b/swt/org.argeo.cms.swt/icons/service_published.gif
deleted file mode 100644 (file)
index 17f771a..0000000
Binary files a/swt/org.argeo.cms.swt/icons/service_published.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/service_referenced.gif b/swt/org.argeo.cms.swt/icons/service_referenced.gif
deleted file mode 100644 (file)
index c24a95f..0000000
Binary files a/swt/org.argeo.cms.swt/icons/service_referenced.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/sort.gif b/swt/org.argeo.cms.swt/icons/sort.gif
deleted file mode 100644 (file)
index 23c5d0b..0000000
Binary files a/swt/org.argeo.cms.swt/icons/sort.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/starting.gif b/swt/org.argeo.cms.swt/icons/starting.gif
deleted file mode 100644 (file)
index 563743d..0000000
Binary files a/swt/org.argeo.cms.swt/icons/starting.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/sync.gif b/swt/org.argeo.cms.swt/icons/sync.gif
deleted file mode 100644 (file)
index b4fa052..0000000
Binary files a/swt/org.argeo.cms.swt/icons/sync.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/user.gif b/swt/org.argeo.cms.swt/icons/user.gif
deleted file mode 100644 (file)
index 90a0014..0000000
Binary files a/swt/org.argeo.cms.swt/icons/user.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/users.gif b/swt/org.argeo.cms.swt/icons/users.gif
deleted file mode 100644 (file)
index 2de7edd..0000000
Binary files a/swt/org.argeo.cms.swt/icons/users.gif and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/workgroup.png b/swt/org.argeo.cms.swt/icons/workgroup.png
deleted file mode 100644 (file)
index 7fef996..0000000
Binary files a/swt/org.argeo.cms.swt/icons/workgroup.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/workgroup.xcf b/swt/org.argeo.cms.swt/icons/workgroup.xcf
deleted file mode 100644 (file)
index f517c82..0000000
Binary files a/swt/org.argeo.cms.swt/icons/workgroup.xcf and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/workspace_connected.png b/swt/org.argeo.cms.swt/icons/workspace_connected.png
deleted file mode 100644 (file)
index 0430baa..0000000
Binary files a/swt/org.argeo.cms.swt/icons/workspace_connected.png and /dev/null differ
diff --git a/swt/org.argeo.cms.swt/icons/workspace_disconnected.png b/swt/org.argeo.cms.swt/icons/workspace_disconnected.png
deleted file mode 100644 (file)
index fddcb8c..0000000
Binary files a/swt/org.argeo.cms.swt/icons/workspace_disconnected.png and /dev/null differ
index 33841a1bb97bfa498e009b1e423dc9e1309338b9..ad347e6e87e267ccff55c5d0ed19d957253cb37a 100644 (file)
@@ -6,6 +6,7 @@ import org.argeo.cms.CmsMsg;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.Selected;
 import org.argeo.cms.swt.dialogs.LightweightDialog;
+import org.argeo.cms.ux.widgets.CmsDialog;
 import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.jface.wizard.IWizard;
@@ -65,7 +66,7 @@ public class CmsWizardDialog extends LightweightDialog implements IWizardContain
                        Button cancelButton = new Button(messageArea, SWT.FLAT);
                        cancelButton.setText(CmsMsg.cancel.lead());
                        cancelButton.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false, 1, 3));
-                       cancelButton.addSelectionListener((Selected) (e) -> closeShell(CANCEL));
+                       cancelButton.addSelectionListener((Selected) (e) -> closeShell(CmsDialog.CANCEL));
                        message = new Label(messageArea, SWT.WRAP);
                        message.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 2));
                        updateMessage();
@@ -207,7 +208,7 @@ public class CmsWizardDialog extends LightweightDialog implements IWizardContain
 
        protected void finishPressed() {
                if (wizard.performFinish())
-                       closeShell(OK);
+                       closeShell(CmsDialog.OK);
        }
 
        private static void setSwitchingFormData(Composite composite) {
index ddb6e1b33b0c12271d92d3ef573075ff11d45085..06bb9be3727c1a81f9ad2dd8f598da15611a38d6 100644 (file)
@@ -17,8 +17,8 @@ import org.argeo.api.cms.ux.CmsImageManager;
 import org.argeo.api.cms.ux.CmsUi;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.util.CurrentSubject;
+import org.argeo.cms.CurrentUser;
+import org.argeo.cms.util.CurrentSubject;
 import org.eclipse.swt.widgets.Display;
 
 public abstract class AbstractSwtCmsView implements CmsView {
index 2427c7610bb141e37d5cd7935519ad1bff5744fc..cf05f6f6455d939f7dd4618ad62e3ec9de78677c 100644 (file)
@@ -9,7 +9,7 @@ import org.argeo.api.acr.ContentSession;
 import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.ux.CmsEditable;
-import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.swt.SwtEditablePart;
 import org.argeo.cms.swt.widgets.ScrolledPage;
 import org.eclipse.swt.SWT;
index 951889eeea24a4d3c435de6744f126c286c9da79..4a35a3bdd2b697e519662858f258989b7b752787 100644 (file)
@@ -10,7 +10,14 @@ public class ContentComposite extends Composite {
 
        public ContentComposite(Composite parent, int style, Content item) {
                super(parent, style);
-               setData(item);
+               if (item != null)
+                       setData(item);
+       }
+
+       public boolean hasContent() {
+               if (getData() == null)
+                       return false;
+               return getData() instanceof Content;
        }
 
        public Content getContent() {
index 57c4da00ce0ea502442080051655c779d8d41d48..f4f5961ca7c22530907c36800c5821a2a64ee587 100644 (file)
@@ -27,10 +27,14 @@ public class SwtSection extends ContentComposite {
                this(section, section, style, node);
        }
 
+       public SwtSection(SwtSection section, int style) {
+               this(section, style, null);
+       }
+
        protected SwtSection(Composite parent, SwtSection parentSection, int style, Content node) {
                super(parent, style, node);
                this.parentSection = parentSection;
-               if (parentSection != null) {
+               if (parentSection != null && hasContent() && parentSection.hasContent()) {
                        relativeDepth = getProvidedContent().getDepth() - parentSection.getProvidedContent().getDepth();
                } else {
                        relativeDepth = 0;
index cd4e37d1937f49e15990585acd5bd4949b0d46a9..b65bc3b6a3a28171ff0719e69dd9c2739d1e4e0c 100644 (file)
@@ -40,6 +40,7 @@ public class SwtTabbedArea extends Composite {
        private StackLayout stackLayout;
 
        private boolean singleTab = false;
+       private String singleTabTitle = null;
 
        public SwtTabbedArea(Composite parent, int style) {
                super(parent, SWT.NONE);
@@ -86,13 +87,15 @@ public class SwtTabbedArea extends Composite {
                        Button title = new Button(sectionHeader, SWT.FLAT);
                        CmsSwtUtils.style(title, selected ? tabSelectedStyle : tabStyle);
                        title.setLayoutData(CmsSwtUtils.fillWidth());
-                       title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode())));
+                       title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getContent())));
                        Content node = section.getContent();
 
                        // FIXME find a standard way to display titles
                        String titleStr = node.getName().getLocalPart();
-                       
-                       // TODO internationalize
+                       if (singleTab && singleTabTitle != null)
+                               titleStr = singleTabTitle;
+
+                       // TODO internationalise
                        title.setText(titleStr);
                        if (!singleTab) {
                                ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
@@ -119,7 +122,7 @@ public class SwtTabbedArea extends Composite {
                        return;
                }
                SwtSection section = (SwtSection) body.getChildren()[0];
-               previousNode = (ProvidedContent) section.getNode();
+               previousNode = (ProvidedContent) section.getContent();
                if (previousNode == null) {// empty state
                        previousNode = (ProvidedContent) context;
                        previousUiProvider = uiProvider;
@@ -229,7 +232,7 @@ public class SwtTabbedArea extends Composite {
        public Content getCurrentContext() {
                SwtSection section = getCurrentSection();
                if (section != null) {
-                       return section.getNode();
+                       return section.getContent();
                } else {
                        return null;
                }
@@ -255,4 +258,8 @@ public class SwtTabbedArea extends Composite {
                this.singleTab = singleTab;
        }
 
+       public void setSingleTabTitle(String singleTabTitle) {
+               this.singleTabTitle = singleTabTitle;
+       }
+
 }
index e66549216db6bd0ac95ba3cf2cb9a11d08ef30bc..a3d533e2fb879b3d43bf222fd42736c1a94d0205 100644 (file)
@@ -10,8 +10,8 @@ import javax.xml.namespace.QName;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.widgets.SwtTreeView;
 import org.argeo.cms.swt.widgets.SwtTableView;
+import org.argeo.cms.swt.widgets.SwtTreeView;
 import org.argeo.cms.ux.acr.ContentHierarchicalPart;
 import org.argeo.cms.ux.widgets.Column;
 import org.argeo.cms.ux.widgets.DefaultTabularPart;
@@ -37,6 +37,13 @@ public class AcrContentTreeView extends Composite {
                split.setLayoutData(CmsSwtUtils.fillAll());
 
                ContentHierarchicalPart contentPart = new ContentHierarchicalPart();
+               contentPart.addColumn((model) -> {
+                       try {
+                               return NamespaceUtils.toPrefixedName(model.getName());
+                       } catch (IllegalStateException e) {
+                               return model.getName().toString();
+                       }
+               });
                contentPart.setInput(rootContent);
 
                new SwtTreeView<>(split, getStyle(), contentPart);
index b0c36c6024fe587ac7dfceeee2598c10c6451a34..37d88f5c3081d15609a8b234bd53754eac60a76c 100644 (file)
@@ -6,7 +6,7 @@ import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.UnsupportedCallbackException;
 
-import org.argeo.eclipse.ui.dialogs.LightweightDialog;
+import org.argeo.cms.swt.dialogs.LightweightDialog;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
index dedf61dea0f31acd0a4ac01e90a00218d5b2abc9..abb8227cd7de150f3421986370d9371c4231ef7f 100644 (file)
@@ -4,10 +4,11 @@ import java.util.Arrays;
 import java.util.concurrent.Callable;
 
 import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.directory.CmsUserManager;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.cms.CmsMsg;
-import org.argeo.cms.CmsUserManager;
 import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.widgets.CmsDialog;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
@@ -46,17 +47,17 @@ public class ChangePasswordDialog extends CmsMessageDialog {
                        if (Arrays.equals(newPassword.getTextChars(), confirmPassword.getTextChars())) {
                                try {
                                        cmsUserManager.changeOwnPassword(previousPassword.getTextChars(), newPassword.getTextChars());
-                                       return OK;
+                                       return CmsDialog.OK;
                                } catch (Exception e1) {
                                        log.error("Could not change password", e1);
                                        cancel();
                                        CmsMessageDialog.openError(CmsMsg.invalidPassword.lead());
-                                       return CANCEL;
+                                       return CmsDialog.CANCEL;
                                }
                        } else {
                                cancel();
                                CmsMessageDialog.openError(CmsMsg.repeatNewPassword.lead());
-                               return CANCEL;
+                               return CmsDialog.CANCEL;
                        }
                };
 
@@ -67,7 +68,7 @@ public class ChangePasswordDialog extends CmsMessageDialog {
        @Override
        protected void okPressed() {
                Integer returnCode = cmsView.doAs(doIt);
-               if (returnCode.equals(OK)) {
+               if (returnCode.equals(CmsDialog.OK)) {
                        super.okPressed();
                        CmsMessageDialog.openInformation(CmsMsg.passwordChanged.lead());
                }
index 91885c74b21deddf70c28a066cc283721e0e0c51..2fed951992f41c55d937012eff89f44ca683f260 100644 (file)
@@ -7,6 +7,7 @@ import java.io.StringWriter;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.cms.CmsMsg;
 import org.argeo.cms.swt.Selected;
+import org.argeo.cms.ux.widgets.CmsDialog;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.GridData;
@@ -85,7 +86,7 @@ public class CmsFeedback extends LightweightDialog {
                Button close = new Button(parent, SWT.FLAT);
                close.setText(CmsMsg.close.lead());
                close.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
-               close.addSelectionListener((Selected) (e) -> closeShell(OK));
+               close.addSelectionListener((Selected) (e) -> closeShell(CmsDialog.OK));
 
                if (exception != null) {
                        stack = new Text(parent, SWT.MULTI | SWT.LEAD | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
index 66e640595de128a69a6a6bfc73b4189a5ac639ba..21308824d4fc570886df9c0dee6bfb185c6e7513 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.swt.dialogs;
 import org.argeo.cms.CmsMsg;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.Selected;
+import org.argeo.cms.ux.widgets.CmsDialog;
 import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.TraverseEvent;
@@ -80,7 +81,7 @@ public class CmsMessageDialog extends LightweightDialog {
                        Button close = new Button(buttons, SWT.FLAT);
                        close.setText(CmsMsg.close.lead());
                        close.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
-                       close.addSelectionListener((Selected) (e) -> closeShell(OK));
+                       close.addSelectionListener((Selected) (e) -> closeShell(CmsDialog.OK));
                        close.setFocus();
                        close.addTraverseListener(traverseListener);
 
@@ -124,15 +125,15 @@ public class CmsMessageDialog extends LightweightDialog {
        }
 
        protected void okPressed() {
-               closeShell(OK);
+               closeShell(CmsDialog.OK);
        }
 
        protected void cancelPressed() {
-               closeShell(CANCEL);
+               closeShell(CmsDialog.CANCEL);
        }
 
        protected void cancel() {
-               closeShell(CANCEL);
+               closeShell(CmsDialog.CANCEL);
        }
 
        protected Point getInitialSize() {
index d74be6aa20c59c3ba4348c56f680f438a3514987..3aec22a14eb791843c912c11057acb810081dacc 100644 (file)
@@ -1,6 +1,7 @@
 package org.argeo.cms.swt.dialogs;
 
 import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.ux.widgets.CmsDialog;
 import org.argeo.eclipse.ui.EclipseUiException;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.FocusEvent;
@@ -20,11 +21,6 @@ import org.eclipse.swt.widgets.Shell;
 public class LightweightDialog {
        private final static CmsLog log = CmsLog.getLog(LightweightDialog.class);
 
-       // must be the same value as org.eclipse.jface.window.Window#OK
-       public final static int OK = 0;
-       // must be the same value as org.eclipse.jface.window.Window#CANCEL
-       public final static int CANCEL = 1;
-
        private Shell parentShell;
        private Shell backgroundShell;
        private Shell foregoundShell;
@@ -88,7 +84,7 @@ public class LightweightDialog {
                                if (hasChildShells())
                                        return;
                                if (returnCode == null)// not yet closed
-                                       closeShell(CANCEL);
+                                       closeShell(CmsDialog.CANCEL);
                        }
 
                        @Override
@@ -113,7 +109,7 @@ public class LightweightDialog {
                                if (hasChildShells())
                                        return;
                                if (returnCode == null)// not yet closed
-                                       closeShell(CANCEL);
+                                       closeShell(CmsDialog.CANCEL);
                        }
                });
                backgroundShell.addDisposeListener((event) -> onClose());
@@ -122,7 +118,7 @@ public class LightweightDialog {
                        block();
                }
                if (returnCode == null)
-                       returnCode = OK;
+                       returnCode = CmsDialog.OK;
                return returnCode;
        }
 
@@ -130,11 +126,11 @@ public class LightweightDialog {
                try {
                        runEventLoop(foregoundShell);
                } catch (ThreadDeath t) {
-                       returnCode = CANCEL;
+                       returnCode = CmsDialog.CANCEL;
                        if (log.isTraceEnabled())
                                log.error("Thread death, canceling dialog", t);
                } catch (Throwable t) {
-                       returnCode = CANCEL;
+                       returnCode = CmsDialog.CANCEL;
                        log.error("Cannot open blocking lightweight dialog", t);
                }
        }
@@ -162,13 +158,13 @@ public class LightweightDialog {
 
        private synchronized void notifyClose() {
                if (returnCode == null)
-                       returnCode = CANCEL;
+                       returnCode = CmsDialog.CANCEL;
                notifyAll();
        }
 
        protected void closeShell(int returnCode) {
                this.returnCode = returnCode;
-               if (CANCEL == returnCode)
+               if (CmsDialog.CANCEL == returnCode)
                        onCancel();
                if (foregoundShell != null && !foregoundShell.isDisposed()) {
                        foregoundShell.close();
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/PickUpUserDialog.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/PickUpUserDialog.java
deleted file mode 100644 (file)
index 23e41ea..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-package org.argeo.cms.swt.useradmin;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.parts.LdifUsersTable;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.dialogs.TrayDialog;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Shell;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Group;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-/** Dialog with a user (or group) list to pick up one */
-public class PickUpUserDialog extends TrayDialog {
-       private static final long serialVersionUID = -1420106871173920369L;
-
-       // Business objects
-       private final UserAdmin userAdmin;
-       private User selectedUser;
-
-       // this page widgets and UI objects
-       private String title;
-       private LdifUsersTable userTableViewerCmp;
-       private TableViewer userViewer;
-       private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
-
-       /**
-        * A dialog to pick up a group or a user, showing a table with default
-        * columns
-        */
-       public PickUpUserDialog(Shell parentShell, String title, UserAdmin userAdmin) {
-               super(parentShell);
-               this.title = title;
-               this.userAdmin = userAdmin;
-
-               columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_ICON), "",
-                               24, 24));
-               columnDefs.add(new ColumnDefinition(
-                               new UserLP(UserLP.COL_DISPLAY_NAME), "Common Name", 150, 100));
-               columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_DOMAIN),
-                               "Domain", 100, 120));
-               columnDefs.add(new ColumnDefinition(new UserLP(UserLP.COL_DN),
-                               "Distinguished Name", 300, 100));
-       }
-
-       /** A dialog to pick up a group or a user */
-       public PickUpUserDialog(Shell parentShell, String title,
-                       UserAdmin userAdmin, List<ColumnDefinition> columnDefs) {
-               super(parentShell);
-               this.title = title;
-               this.userAdmin = userAdmin;
-               this.columnDefs = columnDefs;
-       }
-
-       @Override
-       protected void okPressed() {
-               if (getSelected() == null)
-                       MessageDialog.openError(getShell(), "No user chosen",
-                                       "Please, choose a user or press Cancel.");
-               else
-                       super.okPressed();
-       }
-
-       protected Control createDialogArea(Composite parent) {
-               Composite dialogArea = (Composite) super.createDialogArea(parent);
-               dialogArea.setLayout(new FillLayout());
-
-               Composite bodyCmp = new Composite(dialogArea, SWT.NO_FOCUS);
-               bodyCmp.setLayout(new GridLayout());
-
-               // Create and configure the table
-               userTableViewerCmp = new MyUserTableViewer(bodyCmp, SWT.MULTI
-                               | SWT.H_SCROLL | SWT.V_SCROLL);
-
-               userTableViewerCmp.setColumnDefinitions(columnDefs);
-               userTableViewerCmp.populateWithStaticFilters(false, false);
-               GridData gd = EclipseUiUtils.fillAll();
-               gd.minimumHeight = 300;
-               userTableViewerCmp.setLayoutData(gd);
-               userTableViewerCmp.refresh();
-
-               // Controllers
-               userViewer = userTableViewerCmp.getTableViewer();
-               userViewer.addDoubleClickListener(new MyDoubleClickListener());
-               userViewer
-                               .addSelectionChangedListener(new MySelectionChangedListener());
-
-               parent.pack();
-               return dialogArea;
-       }
-
-       public User getSelected() {
-               if (selectedUser == null)
-                       return null;
-               else
-                       return selectedUser;
-       }
-
-       protected void configureShell(Shell shell) {
-               super.configureShell(shell);
-               shell.setText(title);
-       }
-
-       class MyDoubleClickListener implements IDoubleClickListener {
-               public void doubleClick(DoubleClickEvent evt) {
-                       if (evt.getSelection().isEmpty())
-                               return;
-
-                       Object obj = ((IStructuredSelection) evt.getSelection())
-                                       .getFirstElement();
-                       if (obj instanceof User) {
-                               selectedUser = (User) obj;
-                               okPressed();
-                       }
-               }
-       }
-
-       class MySelectionChangedListener implements ISelectionChangedListener {
-               @Override
-               public void selectionChanged(SelectionChangedEvent event) {
-                       if (event.getSelection().isEmpty()) {
-                               selectedUser = null;
-                               return;
-                       }
-                       Object obj = ((IStructuredSelection) event.getSelection())
-                                       .getFirstElement();
-                       if (obj instanceof Group) {
-                               selectedUser = (Group) obj;
-                       }
-               }
-       }
-
-       private class MyUserTableViewer extends LdifUsersTable {
-               private static final long serialVersionUID = 8467999509931900367L;
-
-               private final String[] knownProps = { LdapAttrs.uid.name(),
-                               LdapAttrs.cn.name(), LdapAttrs.DN };
-
-               private Button showSystemRoleBtn;
-               private Button showUserBtn;
-
-               public MyUserTableViewer(Composite parent, int style) {
-                       super(parent, style);
-               }
-
-               protected void populateStaticFilters(Composite staticFilterCmp) {
-                       staticFilterCmp.setLayout(new GridLayout());
-                       showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK);
-                       showSystemRoleBtn.setText("Show system roles  ");
-
-                       showUserBtn = new Button(staticFilterCmp, SWT.CHECK);
-                       showUserBtn.setText("Show users  ");
-
-                       SelectionListener sl = new SelectionAdapter() {
-                               private static final long serialVersionUID = -7033424592697691676L;
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       refresh();
-                               }
-                       };
-
-                       showSystemRoleBtn.addSelectionListener(sl);
-                       showUserBtn.addSelectionListener(sl);
-               }
-
-               @Override
-               protected List<User> listFilteredElements(String filter) {
-                       Role[] roles;
-                       try {
-                               StringBuilder builder = new StringBuilder();
-
-                               StringBuilder filterBuilder = new StringBuilder();
-                               if (notNull(filter))
-                                       for (String prop : knownProps) {
-                                               filterBuilder.append("(");
-                                               filterBuilder.append(prop);
-                                               filterBuilder.append("=*");
-                                               filterBuilder.append(filter);
-                                               filterBuilder.append("*)");
-                                       }
-
-                               String typeStr = "(" + LdapAttrs.objectClass.name() + "="
-                                               + LdapObjs.groupOfNames.name() + ")";
-                               if ((showUserBtn.getSelection()))
-                                       typeStr = "(|(" + LdapAttrs.objectClass.name() + "="
-                                                       + LdapObjs.inetOrgPerson.name() + ")" + typeStr
-                                                       + ")";
-
-                               if (!showSystemRoleBtn.getSelection())
-                                       typeStr = "(& " + typeStr + "(!(" + LdapAttrs.DN + "=*"
-                                                       + CmsConstants.SYSTEM_ROLES_BASEDN + ")))";
-
-                               if (filterBuilder.length() > 1) {
-                                       builder.append("(&" + typeStr);
-                                       builder.append("(|");
-                                       builder.append(filterBuilder.toString());
-                                       builder.append("))");
-                               } else {
-                                       builder.append(typeStr);
-                               }
-                               roles = userAdmin.getRoles(builder.toString());
-                       } catch (InvalidSyntaxException e) {
-                               throw new EclipseUiException(
-                                               "Unable to get roles with filter: " + filter, e);
-                       }
-                       List<User> users = new ArrayList<User>();
-                       for (Role role : roles)
-                               if (!users.contains(role))
-                                       users.add((User) role);
-                       return users;
-               }
-       }
-
-       private boolean notNull(String string) {
-               if (string == null)
-                       return false;
-               else
-                       return !"".equals(string.trim());
-       }
-}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UserLP.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UserLP.java
deleted file mode 100644 (file)
index b3ab40e..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.argeo.cms.swt.useradmin;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.auth.UserAdminUtils;
-import org.eclipse.jface.resource.JFaceResources;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-
-/** Centralize label providers for the group table */
-class UserLP extends ColumnLabelProvider {
-       private static final long serialVersionUID = -4645930210988368571L;
-
-       final static String COL_ICON = "colID.icon";
-       final static String COL_DN = "colID.dn";
-       final static String COL_DISPLAY_NAME = "colID.displayName";
-       final static String COL_DOMAIN = "colID.domain";
-
-       final String currType;
-
-       // private Font italic;
-       private Font bold;
-
-       UserLP(String colId) {
-               this.currType = colId;
-       }
-
-       @Override
-       public Font getFont(Object element) {
-               // Current user as bold
-               if (UserAdminUtils.isCurrentUser(((User) element))) {
-                       if (bold == null)
-                               bold = JFaceResources.getFontRegistry().defaultFontDescriptor().setStyle(SWT.BOLD)
-                                               .createFont(Display.getCurrent());
-                       return bold;
-               }
-               return null;
-       }
-
-       @Override
-       public Image getImage(Object element) {
-               if (COL_ICON.equals(currType)) {
-                       User user = (User) element;
-                       String dn = user.getName();
-                       if (dn.endsWith(CmsConstants.SYSTEM_ROLES_BASEDN))
-                               return UsersImages.ICON_ROLE;
-                       else if (user.getType() == Role.GROUP)
-                               return UsersImages.ICON_GROUP;
-                       else
-                               return UsersImages.ICON_USER;
-               } else
-                       return null;
-       }
-
-       @Override
-       public String getText(Object element) {
-               User user = (User) element;
-               return getText(user);
-
-       }
-
-       public String getText(User user) {
-               if (COL_DN.equals(currType))
-                       return user.getName();
-               else if (COL_DISPLAY_NAME.equals(currType))
-                       return UserAdminUtils.getCommonName(user);
-               else if (COL_DOMAIN.equals(currType))
-                       return UserAdminUtils.getDomainName(user);
-               else
-                       return "";
-       }
-}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UsersImages.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/UsersImages.java
deleted file mode 100644 (file)
index 21fc5af..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.argeo.cms.swt.useradmin;
-
-import org.argeo.cms.ui.theme.CmsImages;
-import org.eclipse.swt.graphics.Image;
-
-/** Specific users icons. */
-public class UsersImages {
-       private final static String PREFIX = "icons/";
-
-       public final static Image ICON_USER = CmsImages.createImg(PREFIX + "person.png");
-       public final static Image ICON_GROUP = CmsImages.createImg(PREFIX + "group.png");
-       public final static Image ICON_ROLE = CmsImages.createImg(PREFIX + "role.gif");
-       public final static Image ICON_CHANGE_PASSWORD = CmsImages.createImg(PREFIX + "security.gif");
-}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/package-info.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/useradmin/package-info.java
deleted file mode 100644 (file)
index 3597bfc..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** SWT/JFace users management components. */
-package org.argeo.cms.swt.useradmin;
\ No newline at end of file
index efdc45a8a3b41b43b3f1504e563d24ab7ee604b5..e3a268153eba21a946ed5e42be5cfe18b4b404f6 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.swt.widgets;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.ux.widgets.DataPart;
 import org.argeo.cms.ux.widgets.DataView;
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.widgets.Composite;
@@ -16,8 +17,8 @@ public abstract class AbstractSwtView<INPUT, TYPE> extends Composite implements
        protected final SelectionListener selectionListener;
 
        @SuppressWarnings("unchecked")
-       public AbstractSwtView(Composite parent, int style, DataPart<INPUT, TYPE> dataPart) {
-               super(parent, style);
+       public AbstractSwtView(Composite parent, DataPart<INPUT, TYPE> dataPart) {
+               super(parent, SWT.NONE);
                setLayout(CmsSwtUtils.noSpaceGridLayout());
 
                this.dataPart = dataPart;
index a7242b9a976b2315a0cb2212c2336f00611337cb..15d531de1870be2e86b6a7278401d02bc39bb2d9 100644 (file)
@@ -6,6 +6,7 @@ import org.argeo.cms.CmsMsg;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.Selected;
 import org.argeo.cms.swt.dialogs.LightweightDialog;
+import org.argeo.cms.ux.widgets.CmsDialog;
 import org.argeo.cms.ux.widgets.GuidedForm;
 import org.argeo.cms.ux.widgets.GuidedForm.Page;
 import org.argeo.eclipse.ui.EclipseUiUtils;
@@ -65,7 +66,7 @@ public class SwtGuidedFormDialog extends LightweightDialog implements GuidedForm
                        Button cancelButton = new Button(messageArea, SWT.FLAT);
                        cancelButton.setText(CmsMsg.cancel.lead());
                        cancelButton.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false, 1, 3));
-                       cancelButton.addSelectionListener((Selected) (e) -> closeShell(CANCEL));
+                       cancelButton.addSelectionListener((Selected) (e) -> closeShell(CmsDialog.CANCEL));
                        message = new Label(messageArea, SWT.WRAP);
                        message.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 2));
                        updateMessage();
@@ -191,7 +192,7 @@ public class SwtGuidedFormDialog extends LightweightDialog implements GuidedForm
 
        protected void finishPressed() {
                if (guidedForm.performFinish())
-                       closeShell(OK);
+                       closeShell(CmsDialog.OK);
        }
 
        private static void setSwitchingFormData(Composite composite) {
index b136f36e16c73cb03ba615160a453f5c4fa14ff3..3291980f650d15b3eaea58d36fa4550abd122774 100644 (file)
@@ -22,10 +22,10 @@ public class SwtTableView<INPUT, T> extends AbstractSwtView<INPUT, T> {
        private CmsSwtTheme theme;
 
        public SwtTableView(Composite parent, int style, TabularPart<INPUT, T> tabularPart) {
-               super(parent, style, tabularPart);
+               super(parent, tabularPart);
                theme = CmsSwtUtils.getCmsTheme(parent);
 
-               table = new Table(this, SWT.VIRTUAL | SWT.BORDER);
+               table = new Table(this, SWT.VIRTUAL | style);
                table.setLinesVisible(true);
                table.setLayoutData(CmsSwtUtils.fillAll());
 
@@ -60,9 +60,9 @@ public class SwtTableView<INPUT, T> extends AbstractSwtView<INPUT, T> {
 
        protected void refreshItem(TableItem item) {
                int row = getTable().indexOf(item);
+               T data = tabularPart.getData(row);
                for (int i = 0; i < tabularPart.getColumnCount(); i++) {
                        Column<T> column = tabularPart.getColumn(i);
-                       T data = tabularPart.getData(row);
                        item.setData(data);
                        String text = data != null ? column.getText(data) : "";
                        if (text != null)
@@ -75,6 +75,11 @@ public class SwtTableView<INPUT, T> extends AbstractSwtView<INPUT, T> {
                }
        }
 
+       @Override
+       public void notifyItemCountChange() {
+               table.setItemCount(tabularPart.getItemCount());
+       }
+
        protected Table getTable() {
                return table;
        }
index 79543e9f89d938f583a9c05d3c1a5aba4bfe5b37..778ed41387459453c5625eb899e27b5f7e80f9b6 100644 (file)
@@ -2,9 +2,11 @@ package org.argeo.cms.swt.widgets;
 
 import java.util.List;
 
+import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.ux.CmsIcon;
 import org.argeo.cms.swt.CmsSwtTheme;
 import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ux.widgets.Column;
 import org.argeo.cms.ux.widgets.HierarchicalPart;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Image;
@@ -14,6 +16,8 @@ import org.eclipse.swt.widgets.TreeItem;
 
 /** View of a {@link HierarchicalPart} based on a {@link Tree}. */
 public class SwtTreeView<T> extends AbstractSwtView<T, T> {
+       private final static CmsLog log = CmsLog.getLog(SwtTreeView.class);
+
        private static final long serialVersionUID = -6247710601465713047L;
 
        private final Tree tree;
@@ -22,10 +26,10 @@ public class SwtTreeView<T> extends AbstractSwtView<T, T> {
        private CmsSwtTheme theme;
 
        public SwtTreeView(Composite parent, int style, HierarchicalPart<T> hierarchicalPart) {
-               super(parent, style, hierarchicalPart);
+               super(parent, hierarchicalPart);
                theme = CmsSwtUtils.getCmsTheme(parent);
 
-               tree = new Tree(this, SWT.BORDER);
+               tree = new Tree(this, style);
                tree.setLayoutData(CmsSwtUtils.fillAll());
                this.hierarchicalPart = hierarchicalPart;
 
@@ -42,7 +46,12 @@ public class SwtTreeView<T> extends AbstractSwtView<T, T> {
 
                List<T> rootItems = hierarchicalPart.getChildren(hierarchicalPart.getInput());
                for (T child : rootItems) {
-                       addTreeItem(null, child);
+                       try {
+                               addTreeItem(null, child);
+                       } catch (Exception e) {
+                               if (log.isTraceEnabled())
+                                       log.error("Cannot retrieve child", e);
+                       }
                }
 
                tree.addListener(SWT.Expand, event -> {
@@ -68,21 +77,30 @@ public class SwtTreeView<T> extends AbstractSwtView<T, T> {
        protected TreeItem addTreeItem(TreeItem parent, T data) {
                TreeItem item = parent == null ? new TreeItem(tree, SWT.NONE) : new TreeItem(parent, SWT.NONE);
                item.setData(data);
-               String txt = hierarchicalPart.getText(data);
-               if (txt != null)
-                       item.setText(hierarchicalPart.getText(data));
-               CmsIcon icon = hierarchicalPart.getIcon(data);
-               if (icon != null) {
-                       Image image = theme.getSmallIcon(icon);
-                       item.setImage(image);
+               for (int i = 0; i < hierarchicalPart.getColumnCount(); i++) {
+                       Column<T> column = hierarchicalPart.getColumn(i);
+                       String txt = column.getText(data);
+                       if (txt != null)
+                               item.setText(txt);
+                       CmsIcon icon = column.getIcon(data);
+                       if (icon != null) {
+                               Image image = theme.getSmallIcon(icon);
+                               item.setImage(image);
+                       }
                }
-               // TODO optimize
+               // TODO optimise
                List<T> grandChildren = hierarchicalPart.getChildren(data);
                if (grandChildren.size() != 0)
                        new TreeItem(item, SWT.NONE);
                return item;
        }
 
+       @Override
+       public void notifyItemCountChange() {
+               // TODO what to update ?
+
+       }
+
        protected Tree getTree() {
                return tree;
        }
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/ui/theme/CmsImages.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/ui/theme/CmsImages.java
deleted file mode 100644 (file)
index 1c4d79e..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.argeo.cms.ui.theme;
-
-import java.net.URL;
-
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Display;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-public class CmsImages {
-       private static BundleContext themeBc = FrameworkUtil.getBundle(CmsImages.class).getBundleContext();
-
-       final public static String ICONS_BASE = "icons/";
-       final public static String TYPES_BASE = ICONS_BASE + "types/";
-       final public static String ACTIONS_BASE = ICONS_BASE + "actions/";
-
-       public static Image createIcon(String name) {
-               return createImg(CmsImages.ICONS_BASE + name);
-       }
-
-       public static Image createAction(String name) {
-               return createImg(CmsImages.ACTIONS_BASE + name);
-       }
-
-       public static Image createType(String name) {
-               return createImg(CmsImages.TYPES_BASE + name);
-       }
-
-       public static Image createImg(String name) {
-               return CmsImages.createDesc(name).createImage(Display.getDefault());
-       }
-
-       public static ImageDescriptor createDesc(String name) {
-               return createDesc(themeBc, name);
-       }
-
-       public static ImageDescriptor createDesc(BundleContext bc, String name) {
-               URL url = bc.getBundle().getResource(name);
-               if (url == null)
-                       return ImageDescriptor.getMissingImageDescriptor();
-               return ImageDescriptor.createFromURL(url);
-       }
-
-       public static Image createImg(BundleContext bc, String name) {
-               return createDesc(bc, name).createImage(Display.getDefault());
-       }
-
-}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/ui/theme/package-info.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/ui/theme/package-info.java
deleted file mode 100644 (file)
index 7d3a260..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo CMS core theme images. */
-package org.argeo.cms.ui.theme;
\ No newline at end of file
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/ErrorFeedback.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/ErrorFeedback.java
deleted file mode 100644 (file)
index a388e74..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-package org.argeo.eclipse.ui.dialogs;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-import org.argeo.api.cms.CmsLog;
-import org.eclipse.jface.dialogs.IMessageProvider;
-import org.eclipse.jface.dialogs.TitleAreaDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Generic error dialog to be used in try/catch blocks.
- * 
- * @deprecated Use CMS dialogs instead.
- */
-@Deprecated
-public class ErrorFeedback extends TitleAreaDialog {
-       private static final long serialVersionUID = -8918084784628179044L;
-
-       private final static CmsLog log = CmsLog.getLog(ErrorFeedback.class);
-
-       private final String message;
-       private final Throwable exception;
-
-       public static void show(String message, Throwable e) {
-               // rethrow ThreaDeath in order to make sure that RAP will properly clean
-               // up the UI thread
-               if (e instanceof ThreadDeath)
-                       throw (ThreadDeath) e;
-
-               new ErrorFeedback(newShell(), message, e).open();
-       }
-
-       public static void show(String message) {
-               new ErrorFeedback(newShell(), message, null).open();
-       }
-
-       private static Shell newShell() {
-               return new Shell(getDisplay(), SWT.NO_TRIM);
-       }
-
-       /** Tries to find a display */
-       private static Display getDisplay() {
-               try {
-                       Display display = Display.getCurrent();
-                       if (display != null)
-                               return display;
-                       else
-                               return Display.getDefault();
-               } catch (Exception e) {
-                       return Display.getCurrent();
-               }
-       }
-
-       public ErrorFeedback(Shell parentShell, String message, Throwable e) {
-               super(parentShell);
-               setShellStyle(SWT.NO_TRIM);
-               this.message = message;
-               this.exception = e;
-               log.error(message, e);
-       }
-
-       protected Point getInitialSize() {
-               if (exception != null)
-                       return new Point(800, 600);
-               else
-                       return new Point(400, 300);
-       }
-
-       @Override
-       protected Control createDialogArea(Composite parent) {
-               Composite dialogarea = (Composite) super.createDialogArea(parent);
-               dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               Composite composite = new Composite(dialogarea, SWT.NONE);
-               composite.setLayout(new GridLayout(2, false));
-               composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
-               setMessage(message != null ? message + (exception != null ? ": " + exception.getMessage() : "")
-                               : exception != null ? exception.getMessage() : "Unkown Error", IMessageProvider.ERROR);
-
-               if (exception != null) {
-                       Text stack = new Text(composite, SWT.MULTI | SWT.LEAD | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
-                       stack.setEditable(false);
-                       stack.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-                       StringWriter sw = new StringWriter();
-                       exception.printStackTrace(new PrintWriter(sw));
-                       stack.setText(sw.toString());
-               }
-
-               parent.pack();
-               return composite;
-       }
-
-       protected void configureShell(Shell shell) {
-               super.configureShell(shell);
-               shell.setText("Error");
-       }
-}
\ No newline at end of file
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/FeedbackDialog.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/FeedbackDialog.java
deleted file mode 100644 (file)
index f2715bc..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.argeo.eclipse.ui.dialogs;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Generic lightweight dialog, not based on JFace.
- * 
- * @deprecated Use CMS dialogs instead.
- */
-@Deprecated
-public class FeedbackDialog extends LightweightDialog {
-       private final static CmsLog log = CmsLog.getLog(FeedbackDialog.class);
-
-       private String message;
-       private Throwable exception;
-
-//     private Shell parentShell;
-       private Shell shell;
-
-       public static void show(String message, Throwable e) {
-               // rethrow ThreaDeath in order to make sure that RAP will properly clean
-               // up the UI thread
-               if (e instanceof ThreadDeath)
-                       throw (ThreadDeath) e;
-
-               new FeedbackDialog(getDisplay().getActiveShell(), message, e).open();
-       }
-
-       public static void show(String message) {
-               new FeedbackDialog(getDisplay().getActiveShell(), message, null).open();
-       }
-
-       /** Tries to find a display */
-       private static Display getDisplay() {
-               try {
-                       Display display = Display.getCurrent();
-                       if (display != null)
-                               return display;
-                       else
-                               return Display.getDefault();
-               } catch (Exception e) {
-                       return Display.getCurrent();
-               }
-       }
-
-       public FeedbackDialog(Shell parentShell, String message, Throwable e) {
-               super(parentShell);
-               this.message = message;
-               this.exception = e;
-               log.error(message, e);
-       }
-
-       public int open() {
-               if (shell != null)
-                       throw new EclipseUiException("There is already a shell");
-               shell = new Shell(getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-               shell.setLayout(new GridLayout());
-               // shell.setText("Error");
-               shell.setSize(getInitialSize());
-               createDialogArea(shell);
-               // shell.pack();
-               // shell.layout();
-
-               Rectangle shellBounds = Display.getCurrent().getBounds();// RAP
-               Point dialogSize = shell.getSize();
-               int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2;
-               int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2;
-               shell.setLocation(x, y);
-
-               shell.addShellListener(new ShellAdapter() {
-                       private static final long serialVersionUID = -2701270481953688763L;
-
-                       @Override
-                       public void shellDeactivated(ShellEvent e) {
-                               closeShell();
-                       }
-               });
-
-               shell.open();
-               return OK;
-       }
-
-       protected void closeShell() {
-               shell.close();
-               shell.dispose();
-               shell = null;
-       }
-
-       protected Point getInitialSize() {
-               // if (exception != null)
-               // return new Point(800, 600);
-               // else
-               return new Point(400, 300);
-       }
-
-       protected Control createDialogArea(Composite parent) {
-               Composite dialogarea = new Composite(parent, SWT.NONE);
-               dialogarea.setLayout(new GridLayout());
-               // Composite dialogarea = (Composite) super.createDialogArea(parent);
-               dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
-               Label messageLbl = new Label(dialogarea, SWT.NONE);
-               if (message != null)
-                       messageLbl.setText(message);
-               else if (exception != null)
-                       messageLbl.setText(exception.getLocalizedMessage());
-
-               Composite composite = new Composite(dialogarea, SWT.NONE);
-               composite.setLayout(new GridLayout(2, false));
-               composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
-               if (exception != null) {
-                       Text stack = new Text(composite, SWT.MULTI | SWT.LEAD | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
-                       stack.setEditable(false);
-                       stack.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-                       StringWriter sw = new StringWriter();
-                       exception.printStackTrace(new PrintWriter(sw));
-                       stack.setText(sw.toString());
-               }
-
-               // parent.pack();
-               return composite;
-       }
-}
\ No newline at end of file
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/LightweightDialog.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/LightweightDialog.java
deleted file mode 100644 (file)
index 615e141..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-package org.argeo.eclipse.ui.dialogs;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** Generic lightweight dialog, not based on JFace. */
-@Deprecated
-public class LightweightDialog {
-       private final static CmsLog log = CmsLog.getLog(LightweightDialog.class);
-
-       // must be the same value as org.eclipse.jface.window.Window#OK
-       public final static int OK = 0;
-       // must be the same value as org.eclipse.jface.window.Window#CANCEL
-       public final static int CANCEL = 1;
-
-       private Shell parentShell;
-       private Shell backgroundShell;
-       private Shell foregoundShell;
-
-       private Integer returnCode = null;
-       private boolean block = true;
-
-       private String title;
-
-       /** Tries to find a display */
-       private static Display getDisplay() {
-               try {
-                       Display display = Display.getCurrent();
-                       if (display != null)
-                               return display;
-                       else
-                               return Display.getDefault();
-               } catch (Exception e) {
-                       return Display.getCurrent();
-               }
-       }
-
-       public LightweightDialog(Shell parentShell) {
-               this.parentShell = parentShell;
-       }
-
-       public int open() {
-               if (foregoundShell != null)
-                       throw new EclipseUiException("There is already a shell");
-               backgroundShell = new Shell(parentShell, SWT.ON_TOP);
-               backgroundShell.setFullScreen(true);
-               // if (parentShell != null) {
-               // backgroundShell.setBounds(parentShell.getBounds());
-               // } else
-               // backgroundShell.setMaximized(true);
-               backgroundShell.setAlpha(128);
-               backgroundShell.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
-               foregoundShell = new Shell(backgroundShell, SWT.NO_TRIM | SWT.ON_TOP);
-               if (title != null)
-                       setTitle(title);
-               foregoundShell.setLayout(new GridLayout());
-               foregoundShell.setSize(getInitialSize());
-               createDialogArea(foregoundShell);
-               // shell.pack();
-               // shell.layout();
-
-               Rectangle shellBounds = parentShell != null ? parentShell.getBounds() : Display.getCurrent().getBounds();// RAP
-               Point dialogSize = foregoundShell.getSize();
-               int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2;
-               int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2;
-               foregoundShell.setLocation(x, y);
-
-               foregoundShell.addShellListener(new ShellAdapter() {
-                       private static final long serialVersionUID = -2701270481953688763L;
-
-                       @Override
-                       public void shellDeactivated(ShellEvent e) {
-                               if (hasChildShells())
-                                       return;
-                               if (returnCode == null)// not yet closed
-                                       closeShell(CANCEL);
-                       }
-
-                       @Override
-                       public void shellClosed(ShellEvent e) {
-                               notifyClose();
-                       }
-
-               });
-
-               backgroundShell.open();
-               foregoundShell.open();
-               // after the foreground shell has been opened
-               backgroundShell.addFocusListener(new FocusListener() {
-                       private static final long serialVersionUID = 3137408447474661070L;
-
-                       @Override
-                       public void focusLost(FocusEvent event) {
-                       }
-
-                       @Override
-                       public void focusGained(FocusEvent event) {
-                               if (hasChildShells())
-                                       return;
-                               if (returnCode == null)// not yet closed
-                                       closeShell(CANCEL);
-                       }
-               });
-
-               if (block) {
-                       block();
-               }
-               if (returnCode == null)
-                       returnCode = OK;
-               return returnCode;
-       }
-
-       public void block() {
-               try {
-                       runEventLoop(foregoundShell);
-               } catch (ThreadDeath t) {
-                       returnCode = CANCEL;
-                       if (log.isTraceEnabled())
-                               log.error("Thread death, canceling dialog", t);
-               } catch (Throwable t) {
-                       returnCode = CANCEL;
-                       log.error("Cannot open blocking lightweight dialog", t);
-               }
-       }
-
-       private boolean hasChildShells() {
-               if (foregoundShell == null)
-                       return false;
-               return foregoundShell.getShells().length != 0;
-       }
-
-       // public synchronized int openAndWait() {
-       // open();
-       // while (returnCode == null)
-       // try {
-       // wait(100);
-       // } catch (InterruptedException e) {
-       // // silent
-       // }
-       // return returnCode;
-       // }
-
-       private synchronized void notifyClose() {
-               if (returnCode == null)
-                       returnCode = CANCEL;
-               notifyAll();
-       }
-
-       protected void closeShell(int returnCode) {
-               this.returnCode = returnCode;
-               if (CANCEL == returnCode)
-                       onCancel();
-               if (foregoundShell != null && !foregoundShell.isDisposed()) {
-                       foregoundShell.close();
-                       foregoundShell.dispose();
-                       foregoundShell = null;
-               }
-
-               if (backgroundShell != null && !backgroundShell.isDisposed()) {
-                       backgroundShell.close();
-                       backgroundShell.dispose();
-               }
-       }
-
-       protected Point getInitialSize() {
-               // if (exception != null)
-               // return new Point(800, 600);
-               // else
-               return new Point(600, 400);
-       }
-
-       protected Control createDialogArea(Composite parent) {
-               Composite dialogarea = new Composite(parent, SWT.NONE);
-               dialogarea.setLayout(new GridLayout());
-               dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               return dialogarea;
-       }
-
-       protected Shell getBackgroundShell() {
-               return backgroundShell;
-       }
-
-       protected Shell getForegoundShell() {
-               return foregoundShell;
-       }
-
-       public void setBlockOnOpen(boolean shouldBlock) {
-               block = shouldBlock;
-       }
-
-       public void pack() {
-               foregoundShell.pack();
-       }
-
-       private void runEventLoop(Shell loopShell) {
-               Display display;
-               if (foregoundShell == null) {
-                       display = Display.getCurrent();
-               } else {
-                       display = loopShell.getDisplay();
-               }
-
-               while (loopShell != null && !loopShell.isDisposed()) {
-                       try {
-                               if (!display.readAndDispatch()) {
-                                       display.sleep();
-                               }
-                       } catch (UnsupportedOperationException e) {
-                               throw e;
-                       } catch (Throwable e) {
-                               handleException(e);
-                       }
-               }
-               if (!display.isDisposed())
-                       display.update();
-       }
-
-       protected void handleException(Throwable t) {
-               if (t instanceof ThreadDeath) {
-                       // Don't catch ThreadDeath as this is a normal occurrence when
-                       // the thread dies
-                       throw (ThreadDeath) t;
-               }
-               // Try to keep running.
-               t.printStackTrace();
-       }
-
-       /** @return false, if the dialog should not be closed. */
-       protected boolean onCancel() {
-               return true;
-       }
-
-       public void setTitle(String title) {
-               this.title = title;
-               if (title != null && getForegoundShell() != null)
-                       getForegoundShell().setText(title);
-       }
-
-       public Integer getReturnCode() {
-               return returnCode;
-       }
-
-}
\ No newline at end of file
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/SingleValue.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/SingleValue.java
deleted file mode 100644 (file)
index 8ce9b44..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-package org.argeo.eclipse.ui.dialogs;
-
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.dialogs.IMessageProvider;
-import org.eclipse.jface.dialogs.TitleAreaDialog;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/**
- * Dialog to retrieve a single value.
- * 
- * @deprecated Use CMS dialogs instead.
- */
-@Deprecated
-public class SingleValue extends TitleAreaDialog {
-       private static final long serialVersionUID = 2843538207460082349L;
-
-       private Text valueT;
-       private String value;
-       private final String title, message, label;
-       private final Boolean multiline;
-
-       public static String ask(String label, String message) {
-               SingleValue svd = new SingleValue(label, message);
-               if (svd.open() == Window.OK)
-                       return svd.getString();
-               else
-                       return null;
-       }
-
-       public static Long askLong(String label, String message) {
-               SingleValue svd = new SingleValue(label, message);
-               if (svd.open() == Window.OK)
-                       return svd.getLong();
-               else
-                       return null;
-       }
-
-       public static Double askDouble(String label, String message) {
-               SingleValue svd = new SingleValue(label, message);
-               if (svd.open() == Window.OK)
-                       return svd.getDouble();
-               else
-                       return null;
-       }
-
-       public SingleValue(String label, String message) {
-               this(Display.getDefault().getActiveShell(), label, message, label, false);
-       }
-
-       public SingleValue(Shell parentShell, String title, String message, String label, Boolean multiline) {
-               super(parentShell);
-               this.title = title;
-               this.message = message;
-               this.label = label;
-               this.multiline = multiline;
-       }
-
-       protected Point getInitialSize() {
-               if (multiline)
-                       return new Point(450, 350);
-
-               else
-                       return new Point(400, 270);
-       }
-
-       protected Control createDialogArea(Composite parent) {
-               Composite dialogarea = (Composite) super.createDialogArea(parent);
-               dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               Composite composite = new Composite(dialogarea, SWT.NONE);
-               composite.setLayoutData(EclipseUiUtils.fillAll());
-               GridLayout layout = new GridLayout(2, false);
-               layout.marginWidth = layout.marginHeight = 20;
-               composite.setLayout(layout);
-
-               valueT = createLT(composite, label);
-
-               setMessage(message, IMessageProvider.NONE);
-
-               parent.pack();
-               valueT.setFocus();
-               return composite;
-       }
-
-       @Override
-       protected void okPressed() {
-               value = valueT.getText();
-               super.okPressed();
-       }
-
-       /** Creates label and text. */
-       protected Text createLT(Composite parent, String label) {
-               new Label(parent, SWT.NONE).setText(label);
-               Text text;
-               if (multiline) {
-                       text = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.MULTI);
-                       text.setLayoutData(EclipseUiUtils.fillAll());
-               } else {
-                       text = new Text(parent, SWT.LEAD | SWT.BORDER | SWT.SINGLE);
-                       text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
-               }
-               return text;
-       }
-
-       protected void configureShell(Shell shell) {
-               super.configureShell(shell);
-               shell.setText(title);
-       }
-
-       public String getString() {
-               return value;
-       }
-
-       public Long getLong() {
-               return Long.valueOf(getString());
-       }
-
-       public Double getDouble() {
-               return Double.valueOf(getString());
-       }
-}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/package-info.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/dialogs/package-info.java
deleted file mode 100644 (file)
index d6ab148..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic SWT/JFace dialogs. */
-package org.argeo.eclipse.ui.dialogs;
\ No newline at end of file
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/parts/LdifUsersTable.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/parts/LdifUsersTable.java
deleted file mode 100644 (file)
index 5713905..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-package org.argeo.eclipse.ui.parts;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.util.ViewerUtils;
-import org.eclipse.jface.layout.TableColumnLayout;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ColumnWeightData;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Link;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Text;
-import org.osgi.service.useradmin.User;
-
-/**
- * Generic composite that display a filter and a table viewer to display users
- * (can also be groups)
- * 
- * Warning: this class does not extends <code>TableViewer</code>. Use the
- * getTableViewer method to access it.
- * 
- */
-public abstract class LdifUsersTable extends Composite {
-       private static final long serialVersionUID = -7385959046279360420L;
-
-       // Context
-       // private UserAdmin userAdmin;
-
-       // Configuration
-       private List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
-       private boolean hasFilter;
-       private boolean preventTableLayout = false;
-       private boolean hasSelectionColumn;
-       private int tableStyle;
-
-       // Local UI Objects
-       private TableViewer usersViewer;
-       private Text filterTxt;
-
-       /* EXPOSED METHODS */
-
-       /**
-        * @param parent
-        * @param style
-        */
-       public LdifUsersTable(Composite parent, int style) {
-               super(parent, SWT.NO_FOCUS);
-               this.tableStyle = style;
-       }
-
-       // TODO workaround the bug of the table layout in the Form
-       public LdifUsersTable(Composite parent, int style, boolean preventTableLayout) {
-               super(parent, SWT.NO_FOCUS);
-               this.tableStyle = style;
-               this.preventTableLayout = preventTableLayout;
-       }
-
-       /** This must be called before the call to populate method */
-       public void setColumnDefinitions(List<ColumnDefinition> columnDefinitions) {
-               this.columnDefs = columnDefinitions;
-       }
-
-       /**
-        * 
-        * @param addFilter
-        *            choose to add a field to filter results or not
-        * @param addSelection
-        *            choose to add a column to select some of the displayed results or
-        *            not
-        */
-       public void populate(boolean addFilter, boolean addSelection) {
-               // initialization
-               Composite parent = this;
-               hasFilter = addFilter;
-               hasSelectionColumn = addSelection;
-
-               // Main Layout
-               GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
-               layout.verticalSpacing = 5;
-               this.setLayout(layout);
-               if (hasFilter)
-                       createFilterPart(parent);
-
-               Composite tableComp = new Composite(parent, SWT.NO_FOCUS);
-               tableComp.setLayoutData(EclipseUiUtils.fillAll());
-               usersViewer = createTableViewer(tableComp);
-               usersViewer.setContentProvider(new UsersContentProvider());
-       }
-
-       /**
-        * 
-        * @param showMore
-        *            display static filters on creation
-        * @param addSelection
-        *            choose to add a column to select some of the displayed results or
-        *            not
-        */
-       public void populateWithStaticFilters(boolean showMore, boolean addSelection) {
-               // initialization
-               Composite parent = this;
-               hasFilter = true;
-               hasSelectionColumn = addSelection;
-
-               // Main Layout
-               GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
-               layout.verticalSpacing = 5;
-               this.setLayout(layout);
-               createStaticFilterPart(parent, showMore);
-
-               Composite tableComp = new Composite(parent, SWT.NO_FOCUS);
-               tableComp.setLayoutData(EclipseUiUtils.fillAll());
-               usersViewer = createTableViewer(tableComp);
-               usersViewer.setContentProvider(new UsersContentProvider());
-       }
-
-       /** Enable access to the selected users or groups */
-       public List<User> getSelectedUsers() {
-               if (hasSelectionColumn) {
-                       Object[] elements = ((CheckboxTableViewer) usersViewer).getCheckedElements();
-
-                       List<User> result = new ArrayList<User>();
-                       for (Object obj : elements) {
-                               result.add((User) obj);
-                       }
-                       return result;
-               } else
-                       throw new EclipseUiException(
-                                       "Unvalid request: no selection column " + "has been created for the current table");
-       }
-
-       /** Returns the User table viewer, typically to add doubleclick listener */
-       public TableViewer getTableViewer() {
-               return usersViewer;
-       }
-
-       /**
-        * Force the refresh of the underlying table using the current filter string if
-        * relevant
-        */
-       public void refresh() {
-               String filter = hasFilter ? filterTxt.getText().trim() : null;
-               if ("".equals(filter))
-                       filter = null;
-               refreshFilteredList(filter);
-       }
-
-       /** Effective repository request: caller must implement this method */
-       abstract protected List<User> listFilteredElements(String filter);
-
-       // protected List<User> listFilteredElements(String filter) {
-       // List<User> users = new ArrayList<User>();
-       // try {
-       // Role[] roles = userAdmin.getRoles(filter);
-       // // Display all users and groups
-       // for (Role role : roles)
-       // users.add((User) role);
-       // } catch (InvalidSyntaxException e) {
-       // throw new EclipseUiException("Unable to get roles with filter: "
-       // + filter, e);
-       // }
-       // return users;
-       // }
-
-       /* GENERIC COMPOSITE METHODS */
-       @Override
-       public boolean setFocus() {
-               if (hasFilter)
-                       return filterTxt.setFocus();
-               else
-                       return usersViewer.getTable().setFocus();
-       }
-
-       @Override
-       public void dispose() {
-               super.dispose();
-       }
-
-       /* LOCAL CLASSES AND METHODS */
-       // Will be usefull to rather use a virtual table viewer
-       private void refreshFilteredList(String filter) {
-               List<User> users = listFilteredElements(filter);
-               usersViewer.setInput(users.toArray());
-       }
-
-       private class UsersContentProvider implements IStructuredContentProvider {
-               private static final long serialVersionUID = 1L;
-
-               public Object[] getElements(Object inputElement) {
-                       return (Object[]) inputElement;
-               }
-
-               public void dispose() {
-               }
-
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               }
-       }
-
-       /* MANAGE FILTER */
-       private void createFilterPart(Composite parent) {
-               // Text Area for the filter
-               filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
-               filterTxt.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
-               filterTxt.addModifyListener(new ModifyListener() {
-                       private static final long serialVersionUID = 1L;
-
-                       public void modifyText(ModifyEvent event) {
-                               refreshFilteredList(filterTxt.getText());
-                       }
-               });
-       }
-
-       private void createStaticFilterPart(Composite parent, boolean showMore) {
-               Composite filterComp = new Composite(parent, SWT.NO_FOCUS);
-               filterComp.setLayout(new GridLayout(2, false));
-               filterComp.setLayoutData(EclipseUiUtils.fillWidth());
-               // generic search
-               filterTxt = new Text(filterComp, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
-               filterTxt.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
-               // filterTxt.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL |
-               // GridData.HORIZONTAL_ALIGN_FILL));
-               filterTxt.addModifyListener(new ModifyListener() {
-                       private static final long serialVersionUID = 1L;
-
-                       public void modifyText(ModifyEvent event) {
-                               refreshFilteredList(filterTxt.getText());
-                       }
-               });
-
-               // add static filter abilities
-               Link moreLk = new Link(filterComp, SWT.NONE);
-               Composite staticFilterCmp = new Composite(filterComp, SWT.NO_FOCUS);
-               staticFilterCmp.setLayoutData(EclipseUiUtils.fillWidth(2));
-               populateStaticFilters(staticFilterCmp);
-
-               MoreLinkListener listener = new MoreLinkListener(moreLk, staticFilterCmp, showMore);
-               // initialise the layout
-               listener.refresh();
-               moreLk.addSelectionListener(listener);
-       }
-
-       /** Overwrite to add static filters */
-       protected void populateStaticFilters(Composite staticFilterCmp) {
-       }
-
-       // private void addMoreSL(final Link more) {
-       // more.addSelectionListener( }
-
-       private class MoreLinkListener extends SelectionAdapter {
-               private static final long serialVersionUID = -524987616510893463L;
-               private boolean isShown;
-               private final Composite staticFilterCmp;
-               private final Link moreLk;
-
-               public MoreLinkListener(Link moreLk, Composite staticFilterCmp, boolean isShown) {
-                       this.moreLk = moreLk;
-                       this.staticFilterCmp = staticFilterCmp;
-                       this.isShown = isShown;
-               }
-
-               @Override
-               public void widgetSelected(SelectionEvent e) {
-                       isShown = !isShown;
-                       refresh();
-               }
-
-               public void refresh() {
-                       GridData gd = (GridData) staticFilterCmp.getLayoutData();
-                       if (isShown) {
-                               moreLk.setText("<a> Less... </a>");
-                               gd.heightHint = SWT.DEFAULT;
-                       } else {
-                               moreLk.setText("<a> More... </a>");
-                               gd.heightHint = 0;
-                       }
-                       forceLayout();
-               }
-       }
-
-       private void forceLayout() {
-               LdifUsersTable.this.getParent().layout(true, true);
-       }
-
-       private TableViewer createTableViewer(final Composite parent) {
-
-               int style = tableStyle | SWT.H_SCROLL | SWT.V_SCROLL;
-               if (hasSelectionColumn)
-                       style = style | SWT.CHECK;
-               Table table = new Table(parent, style);
-               TableColumnLayout layout = new TableColumnLayout();
-
-               // TODO the table layout does not works with the scrolled form
-
-               if (preventTableLayout) {
-                       parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-                       table.setLayoutData(EclipseUiUtils.fillAll());
-               } else
-                       parent.setLayout(layout);
-
-               TableViewer viewer;
-               if (hasSelectionColumn)
-                       viewer = new CheckboxTableViewer(table);
-               else
-                       viewer = new TableViewer(table);
-               table.setLinesVisible(true);
-               table.setHeaderVisible(true);
-
-               TableViewerColumn column;
-               // int offset = 0;
-               if (hasSelectionColumn) {
-                       // offset = 1;
-                       column = ViewerUtils.createTableViewerColumn(viewer, "", SWT.NONE, 25);
-                       column.setLabelProvider(new ColumnLabelProvider() {
-                               private static final long serialVersionUID = 1L;
-
-                               @Override
-                               public String getText(Object element) {
-                                       return null;
-                               }
-                       });
-                       layout.setColumnData(column.getColumn(), new ColumnWeightData(25, 25, false));
-
-                       SelectionAdapter selectionAdapter = new SelectionAdapter() {
-                               private static final long serialVersionUID = 1L;
-
-                               boolean allSelected = false;
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       allSelected = !allSelected;
-                                       ((CheckboxTableViewer) usersViewer).setAllChecked(allSelected);
-                               }
-                       };
-                       column.getColumn().addSelectionListener(selectionAdapter);
-               }
-
-               // NodeViewerComparator comparator = new NodeViewerComparator();
-               // TODO enable the sort by click on the header
-               // int i = offset;
-               for (ColumnDefinition colDef : columnDefs)
-                       createTableColumn(viewer, layout, colDef);
-
-               // column = ViewerUtils.createTableViewerColumn(viewer,
-               // colDef.getHeaderLabel(), SWT.NONE, colDef.getColumnSize());
-               // column.setLabelProvider(new CLProvider(colDef.getPropertyName()));
-               // column.getColumn().addSelectionListener(
-               // JcrUiUtils.getNodeSelectionAdapter(i,
-               // colDef.getPropertyType(), colDef.getPropertyName(),
-               // comparator, viewer));
-               // i++;
-               // }
-
-               // IMPORTANT: initialize comparator before setting it
-               // JcrColumnDefinition firstCol = colDefs.get(0);
-               // comparator.setColumn(firstCol.getPropertyType(),
-               // firstCol.getPropertyName());
-               // viewer.setComparator(comparator);
-
-               return viewer;
-       }
-
-       /** Default creation of a column for a user table */
-       private TableViewerColumn createTableColumn(TableViewer tableViewer, TableColumnLayout layout,
-                       ColumnDefinition columnDef) {
-
-               boolean resizable = true;
-               TableViewerColumn tvc = new TableViewerColumn(tableViewer, SWT.NONE);
-               TableColumn column = tvc.getColumn();
-
-               column.setText(columnDef.getLabel());
-               column.setWidth(columnDef.getMinWidth());
-               column.setResizable(resizable);
-
-               ColumnLabelProvider lp = columnDef.getLabelProvider();
-               // add a reference to the display to enable font management
-               // if (lp instanceof UserAdminAbstractLP)
-               // ((UserAdminAbstractLP) lp).setDisplay(tableViewer.getTable()
-               // .getDisplay());
-               tvc.setLabelProvider(lp);
-
-               layout.setColumnData(column, new ColumnWeightData(columnDef.getWeight(), columnDef.getMinWidth(), resizable));
-
-               return tvc;
-       }
-}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/parts/package-info.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/parts/package-info.java
deleted file mode 100644 (file)
index 9e93b11..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic SWT/JFace composites. */
-package org.argeo.eclipse.ui.parts;
\ No newline at end of file
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/util/ViewerUtils.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/util/ViewerUtils.java
deleted file mode 100644 (file)
index 8f4df17..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.argeo.eclipse.ui.util;
-
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.TableViewerColumn;
-import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.TreeColumn;
-
-/**
- * Centralise useful methods to manage JFace Table, Tree and TreeColumn viewers.
- */
-public class ViewerUtils {
-
-       /**
-        * Creates a basic column for the given table. For the time being, we do not
-        * support movable columns.
-        */
-       public static TableColumn createColumn(Table parent, String name, int style, int width) {
-               TableColumn result = new TableColumn(parent, style);
-               result.setText(name);
-               result.setWidth(width);
-               result.setResizable(true);
-               return result;
-       }
-
-       /**
-        * Creates a TableViewerColumn for the given viewer. For the time being, we do
-        * not support movable columns.
-        */
-       public static TableViewerColumn createTableViewerColumn(TableViewer parent, String name, int style, int width) {
-               TableViewerColumn tvc = new TableViewerColumn(parent, style);
-               TableColumn column = tvc.getColumn();
-               column.setText(name);
-               column.setWidth(width);
-               column.setResizable(true);
-               return tvc;
-       }
-
-       // public static TableViewerColumn createTableViewerColumn(TableViewer parent,
-       // Localized name, int style, int width) {
-       // return createTableViewerColumn(parent, name.lead(), style, width);
-       // }
-
-       /**
-        * Creates a TreeViewerColumn for the given viewer. For the time being, we do
-        * not support movable columns.
-        */
-       public static TreeViewerColumn createTreeViewerColumn(TreeViewer parent, String name, int style, int width) {
-               TreeViewerColumn tvc = new TreeViewerColumn(parent, style);
-               TreeColumn column = tvc.getColumn();
-               column.setText(name);
-               column.setWidth(width);
-               column.setResizable(true);
-               return tvc;
-       }
-}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/util/package-info.java b/swt/org.argeo.cms.swt/src/org/argeo/eclipse/ui/util/package-info.java
deleted file mode 100644 (file)
index 798d174..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic SWT/JFace JCR helpers. */
-package org.argeo.eclipse.ui.util;
\ No newline at end of file
diff --git a/swt/rap/org.argeo.cms.e4.rap/OSGI-INF/cms-admin-rap.xml b/swt/rap/org.argeo.cms.e4.rap/OSGI-INF/cms-admin-rap.xml
deleted file mode 100644 (file)
index 1f688ba..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" configuration-policy="optional" name="CMS Admin RAP">
-   <implementation class="org.argeo.cms.e4.rap.CmsE4AdminApp"/>
-   <service>
-      <provide interface="org.eclipse.rap.rwt.application.ApplicationConfiguration"/>
-      <property name="contextName" type="String" value="cms"/>
-   </service>
-</scr:component>
index 29ce1708ab689b2ddcc8ab3684aec8a4463ac990..6db081fc29107f6b74ca5e2981f3f63dbba180b1 100644 (file)
@@ -1,6 +1,3 @@
-Bundle-ActivationPolicy: lazy
-Service-Component: OSGI-INF/cms-admin-rap.xml
-
 Import-Package: \
 org.argeo.api.acr, \
 org.eclipse.swt,\
@@ -8,4 +5,5 @@ org.eclipse.swt.graphics,\
 org.eclipse.e4.ui.workbench,\
 org.eclipse.rap.rwt.client,\
 org.eclipse.nebula.widgets.richtext;resolution:=optional,\
+org.eclipse.*;resolution:=optional,\
 *
diff --git a/swt/rap/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java b/swt/rap/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsE4AdminApp.java
deleted file mode 100644 (file)
index a3e127a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.argeo.cms.e4.rap;
-
-import org.eclipse.rap.rwt.application.Application;
-
-/**
- * Access to canonical views of the core CMS concepts, useful for devleopers and
- * operators.
- */
-public class CmsE4AdminApp extends AbstractRapE4App {
-       @Override
-       protected void addEntryPoints(Application application) {
-               addE4EntryPoint(application, "/devops", "org.argeo.cms.e4/e4xmi/cms-devops.e4xmi",
-                               customise("Argeo CMS DevOps"));
-       }
-
-}
index 7d4cd83315721d3227e801ddc5ea5bb280b00898..cdd87fd3f54696688270d7751349efbe1b761b96 100644 (file)
@@ -15,7 +15,7 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.ux.CmsImageManager;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.SimpleSwtUxContext;
 import org.argeo.cms.swt.acr.AcrSwtImageManager;
index 1bca333c99d5c5b7988883add6cbd2d9f8948424..764234e18d010db581446ccd99532e02b57b05b7 100644 (file)
@@ -2,7 +2,6 @@ package org.argeo.cms.e4.rap;
 
 import java.util.Enumeration;
 
-import org.apache.commons.io.FilenameUtils;
 import org.argeo.api.cms.CmsLog;
 import org.eclipse.rap.rwt.application.Application;
 import org.osgi.framework.Bundle;
@@ -21,7 +20,8 @@ public class SimpleRapE4App extends AbstractRapE4App {
                        String p = paths.nextElement();
                        if (p.endsWith(".e4xmi")) {
                                String e4xmiPath = bundle.getSymbolicName() + '/' + p;
-                               String name = '/' + FilenameUtils.removeExtension(FilenameUtils.getName(p));
+                               // FIXME deal with base name
+                               String name=null;// = '/' + FilenameUtils.removeExtension(FilenameUtils.getName(p));
                                addE4EntryPoint(application, name, e4xmiPath, getBaseProperties());
                                if (log.isDebugEnabled())
                                        log.debug("Registered " + e4xmiPath + " as " + getContextName() + name);
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/.classpath b/swt/rap/org.argeo.cms.swt.rap.cli/.classpath
deleted file mode 100644 (file)
index 81fe078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/.project b/swt/rap/org.argeo.cms.swt.rap.cli/.project
deleted file mode 100644 (file)
index 7b3af9d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.cms.swt.rap.cli</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/jni-config.json b/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/jni-config.json
deleted file mode 100644 (file)
index 25530bb..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-[
-{
-  "name":"java.lang.Boolean",
-  "methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.ClassLoader",
-  "methods":[
-    {"name":"getPlatformClassLoader","parameterTypes":[] }, 
-    {"name":"loadClass","parameterTypes":["java.lang.String"] }
-  ]
-},
-{
-  "name":"jdk.internal.loader.ClassLoaders$PlatformClassLoader"
-},
-{
-  "name":"org.graalvm.jniutils.JNIExceptionWrapperEntryPoints",
-  "methods":[{"name":"getClassName","parameterTypes":["java.lang.Class"] }]
-},
-{
-  "name":"sun.management.VMManagementImpl",
-  "fields":[
-    {"name":"compTimeMonitoringSupport"}, 
-    {"name":"currentThreadCpuTimeSupport"}, 
-    {"name":"objectMonitorUsageSupport"}, 
-    {"name":"otherThreadCpuTimeSupport"}, 
-    {"name":"remoteDiagnosticCommandsSupport"}, 
-    {"name":"synchronizerUsageSupport"}, 
-    {"name":"threadAllocatedMemorySupport"}, 
-    {"name":"threadContentionMonitoringSupport"}
-  ]
-}
-]
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/predefined-classes-config.json b/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/predefined-classes-config.json
deleted file mode 100644 (file)
index 0e79b2c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-[
-  {
-    "type":"agent-extracted",
-    "classes":[
-    ]
-  }
-]
-
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/proxy-config.json b/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/proxy-config.json
deleted file mode 100644 (file)
index 5d1d13d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-[
-  {
-    "interfaces":["javax.servlet.http.HttpServletRequest"]}
-  ,
-  {
-    "interfaces":["javax.servlet.http.HttpServletResponse"]}
-  
-]
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/reflect-config.json b/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/reflect-config.json
deleted file mode 100644 (file)
index e9910e1..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-[
-{
-  "name":"[B"
-},
-{
-  "name":"[Ljava.lang.String;"
-},
-{
-  "name":"[Lorg.eclipse.swt.widgets.TableColumn;"
-},
-{
-  "name":"[Lorg.eclipse.swt.widgets.TreeColumn;"
-},
-{
-  "name":"[Lsun.security.pkcs.SignerInfo;"
-},
-{
-  "name":"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"java.lang.Boolean",
-  "queriedMethods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.Byte",
-  "queriedMethods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.Class"
-},
-{
-  "name":"java.lang.Double",
-  "queriedMethods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.Float",
-  "queriedMethods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.Integer",
-  "queriedMethods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.Long",
-  "queriedMethods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.Object",
-  "queriedMethods":[
-    {"name":"equals","parameterTypes":["java.lang.Object"] }, 
-    {"name":"hashCode","parameterTypes":[] }, 
-    {"name":"toString","parameterTypes":[] }
-  ]
-},
-{
-  "name":"java.lang.Short",
-  "queriedMethods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
-},
-{
-  "name":"java.lang.String"
-},
-{
-  "name":"java.lang.management.ManagementFactory",
-  "methods":[{"name":"getRuntimeMXBean","parameterTypes":[] }]
-},
-{
-  "name":"java.lang.management.RuntimeMXBean",
-  "methods":[{"name":"getUptime","parameterTypes":[] }]
-},
-{
-  "name":"java.security.AlgorithmParametersSpi"
-},
-{
-  "name":"java.security.SecureRandomParameters"
-},
-{
-  "name":"java.util.Date"
-},
-{
-  "name":"javax.security.auth.login.Configuration$Parameters"
-},
-{
-  "name":"javax.security.auth.x500.X500Principal",
-  "fields":[{"name":"thisX500Name"}],
-  "queriedMethods":[{"name":"<init>","parameterTypes":["sun.security.x509.X500Name"] }]
-},
-{
-  "name":"javax.servlet.ServletRequest",
-  "queriedMethods":[
-    {"name":"getAsyncContext","parameterTypes":[] }, 
-    {"name":"getAttribute","parameterTypes":["java.lang.String"] }, 
-    {"name":"getAttributeNames","parameterTypes":[] }, 
-    {"name":"getCharacterEncoding","parameterTypes":[] }, 
-    {"name":"getContentLength","parameterTypes":[] }, 
-    {"name":"getContentLengthLong","parameterTypes":[] }, 
-    {"name":"getContentType","parameterTypes":[] }, 
-    {"name":"getDispatcherType","parameterTypes":[] }, 
-    {"name":"getInputStream","parameterTypes":[] }, 
-    {"name":"getLocalAddr","parameterTypes":[] }, 
-    {"name":"getLocalName","parameterTypes":[] }, 
-    {"name":"getLocalPort","parameterTypes":[] }, 
-    {"name":"getLocale","parameterTypes":[] }, 
-    {"name":"getLocales","parameterTypes":[] }, 
-    {"name":"getParameter","parameterTypes":["java.lang.String"] }, 
-    {"name":"getParameterMap","parameterTypes":[] }, 
-    {"name":"getParameterNames","parameterTypes":[] }, 
-    {"name":"getParameterValues","parameterTypes":["java.lang.String"] }, 
-    {"name":"getProtocol","parameterTypes":[] }, 
-    {"name":"getReader","parameterTypes":[] }, 
-    {"name":"getRealPath","parameterTypes":["java.lang.String"] }, 
-    {"name":"getRemoteAddr","parameterTypes":[] }, 
-    {"name":"getRemoteHost","parameterTypes":[] }, 
-    {"name":"getRemotePort","parameterTypes":[] }, 
-    {"name":"getRequestDispatcher","parameterTypes":["java.lang.String"] }, 
-    {"name":"getScheme","parameterTypes":[] }, 
-    {"name":"getServerName","parameterTypes":[] }, 
-    {"name":"getServerPort","parameterTypes":[] }, 
-    {"name":"getServletContext","parameterTypes":[] }, 
-    {"name":"isAsyncStarted","parameterTypes":[] }, 
-    {"name":"isAsyncSupported","parameterTypes":[] }, 
-    {"name":"isSecure","parameterTypes":[] }, 
-    {"name":"removeAttribute","parameterTypes":["java.lang.String"] }, 
-    {"name":"setAttribute","parameterTypes":["java.lang.String","java.lang.Object"] }, 
-    {"name":"setCharacterEncoding","parameterTypes":["java.lang.String"] }, 
-    {"name":"startAsync","parameterTypes":[] }, 
-    {"name":"startAsync","parameterTypes":["javax.servlet.ServletRequest","javax.servlet.ServletResponse"] }
-  ]
-},
-{
-  "name":"javax.servlet.ServletResponse"
-},
-{
-  "name":"javax.servlet.http.HttpServletRequest",
-  "methods":[{"name":"<init>","parameterTypes":["java.lang.reflect.InvocationHandler"] }],
-  "queriedMethods":[
-    {"name":"authenticate","parameterTypes":["javax.servlet.http.HttpServletResponse"] }, 
-    {"name":"changeSessionId","parameterTypes":[] }, 
-    {"name":"getAuthType","parameterTypes":[] }, 
-    {"name":"getContextPath","parameterTypes":[] }, 
-    {"name":"getCookies","parameterTypes":[] }, 
-    {"name":"getDateHeader","parameterTypes":["java.lang.String"] }, 
-    {"name":"getHeader","parameterTypes":["java.lang.String"] }, 
-    {"name":"getHeaderNames","parameterTypes":[] }, 
-    {"name":"getHeaders","parameterTypes":["java.lang.String"] }, 
-    {"name":"getHttpServletMapping","parameterTypes":[] }, 
-    {"name":"getIntHeader","parameterTypes":["java.lang.String"] }, 
-    {"name":"getMethod","parameterTypes":[] }, 
-    {"name":"getPart","parameterTypes":["java.lang.String"] }, 
-    {"name":"getParts","parameterTypes":[] }, 
-    {"name":"getPathInfo","parameterTypes":[] }, 
-    {"name":"getPathTranslated","parameterTypes":[] }, 
-    {"name":"getQueryString","parameterTypes":[] }, 
-    {"name":"getRemoteUser","parameterTypes":[] }, 
-    {"name":"getRequestURI","parameterTypes":[] }, 
-    {"name":"getRequestURL","parameterTypes":[] }, 
-    {"name":"getRequestedSessionId","parameterTypes":[] }, 
-    {"name":"getServletPath","parameterTypes":[] }, 
-    {"name":"getSession","parameterTypes":[] }, 
-    {"name":"getSession","parameterTypes":["boolean"] }, 
-    {"name":"getTrailerFields","parameterTypes":[] }, 
-    {"name":"getUserPrincipal","parameterTypes":[] }, 
-    {"name":"isRequestedSessionIdFromCookie","parameterTypes":[] }, 
-    {"name":"isRequestedSessionIdFromURL","parameterTypes":[] }, 
-    {"name":"isRequestedSessionIdFromUrl","parameterTypes":[] }, 
-    {"name":"isRequestedSessionIdValid","parameterTypes":[] }, 
-    {"name":"isTrailerFieldsReady","parameterTypes":[] }, 
-    {"name":"isUserInRole","parameterTypes":["java.lang.String"] }, 
-    {"name":"login","parameterTypes":["java.lang.String","java.lang.String"] }, 
-    {"name":"logout","parameterTypes":[] }, 
-    {"name":"newPushBuilder","parameterTypes":[] }, 
-    {"name":"upgrade","parameterTypes":["java.lang.Class"] }
-  ]
-},
-{
-  "name":"javax.servlet.http.HttpServletResponse"
-},
-{
-  "name":"org.apache.xerces.impl.dv.dtd.DTDDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.dv.dtd.XML11DTDDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.dv.xs.ExtendedSchemaDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.impl.xs.XSMessageFormatter",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.apache.xerces.parsers.XIncludeAwareParserConfiguration",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.argeo.cms.auth.AnonymousLoginModule",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.argeo.cms.auth.DataAdminLoginModule",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.argeo.cms.auth.IdentLoginModule",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.argeo.cms.auth.RemoteSessionLoginModule",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.argeo.cms.auth.UserAdminLoginModule",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.jetty.servlet.DefaultServlet",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.jetty.util.TypeUtil",
-  "methods":[
-    {"name":"getClassLoaderLocation","parameterTypes":["java.lang.Class"] }, 
-    {"name":"getCodeSourceLocation","parameterTypes":["java.lang.Class"] }, 
-    {"name":"getModuleLocation","parameterTypes":["java.lang.Class"] }, 
-    {"name":"getSystemClassLoaderLocation","parameterTypes":["java.lang.Class"] }
-  ]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.client.BrowserNavigationImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.client.ClientInfoImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.client.ExitConfirmationImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.client.StartupParametersImpl",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.client.WebClientMessages",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle",
-  "methods":[{"name":"<init>","parameterTypes":["org.eclipse.rap.rwt.internal.application.ApplicationContextImpl"] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.lifecycle.RequestCounter",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.remote.RemoteObjectRegistry",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.serverpush.ServerPushManager",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.rap.rwt.internal.textsize.ProbeResultStore",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.SWT",
-  "allDeclaredFields":true
-},
-{
-  "name":"org.eclipse.swt.graphics.Color",
-  "methods":[{"name":"<init>","parameterTypes":["int"] }]
-},
-{
-  "name":"org.eclipse.swt.graphics.Font",
-  "methods":[{"name":"<init>","parameterTypes":["org.eclipse.swt.graphics.FontData"] }]
-},
-{
-  "name":"org.eclipse.swt.internal.image.GIFFileFormat",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.image.JPEGFileFormat",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.image.PNGFileFormat",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.image.WinBMPFileFormat",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.image.WinICOFileFormat",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.widgets.IdGenerator",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.widgets.displaykit.DisplayLCA",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.widgets.scrollbarkit.ScrollBarThemeAdapter",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.widgets.shellkit.ShellThemeAdapter",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.widgets.tablekit.TableThemeAdapter",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"org.eclipse.swt.internal.widgets.treekit.TreeThemeAdapter",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.ConfigFile$Spi",
-  "methods":[{"name":"<init>","parameterTypes":["javax.security.auth.login.Configuration$Parameters"] }]
-},
-{
-  "name":"sun.security.provider.DRBG",
-  "methods":[{"name":"<init>","parameterTypes":["java.security.SecureRandomParameters"] }]
-},
-{
-  "name":"sun.security.provider.DSAKeyFactory",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.DSAParameters",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.NativePRNG",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.SHA",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.SHA2$SHA256",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.provider.X509Factory",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.rsa.RSAKeyFactory$Legacy",
-  "methods":[{"name":"<init>","parameterTypes":[] }]
-},
-{
-  "name":"sun.security.util.ObjectIdentifier"
-},
-{
-  "name":"sun.security.x509.AuthorityKeyIdentifierExtension",
-  "methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
-},
-{
-  "name":"sun.security.x509.BasicConstraintsExtension",
-  "methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
-},
-{
-  "name":"sun.security.x509.CertificateExtensions"
-},
-{
-  "name":"sun.security.x509.ExtendedKeyUsageExtension",
-  "methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
-},
-{
-  "name":"sun.security.x509.KeyUsageExtension",
-  "methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
-},
-{
-  "name":"sun.security.x509.SubjectKeyIdentifierExtension",
-  "methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
-}
-]
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/resource-config.json b/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/resource-config.json
deleted file mode 100644 (file)
index 0f3300a..0000000
+++ /dev/null
@@ -1,735 +0,0 @@
-{
-  "resources":{
-  "includes":[
-    {
-      "pattern":"\\QMETA-INF/MANIFEST.MF\\E"
-    }, 
-    {
-      "pattern":"\\QMETA-INF/services/javax.xml.parsers.DocumentBuilderFactory\\E"
-    }, 
-    {
-      "pattern":"\\QMETA-INF/services/javax.xml.validation.SchemaFactory\\E"
-    }, 
-    {
-      "pattern":"\\QMETA-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder\\E"
-    }, 
-    {
-      "pattern":"\\Qclient.files\\E"
-    }, 
-    {
-      "pattern":"\\Qclient.js\\E"
-    }, 
-    {
-      "pattern":"\\Qjetty-dir.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/DSMLv2.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/SVG.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/XForms-11-Schema.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/XMLSchema.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/cr.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/docbook.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/schema-for-xslt20.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/xlink.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/xml-events-attribs-1.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/acr/schemas/xml.xsd\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/argeo/cms/internal/runtime/jaas.cfg\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/jetty/http/encoding.properties\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/jetty/http/mime.properties\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/jetty/version/build.properties\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/nebula/widgets/grid/internal/gridkit/Grid.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/nebula/widgets/grid/internal/gridkit/Grid.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/nebula/widgets/grid/internal/gridkit/Grid.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/rap/rwt/internal/service/rwt-index.html\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/rap/rwt/internal/widgets/dropdownkit/DropDown.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/rap/rwt/internal/widgets/dropdownkit/DropDown.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/rap/rwt/internal/widgets/dropdownkit/DropDown.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/rap/rwt/internal/widgets/fileuploadkit/FileUpload.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/rap/rwt/internal/widgets/fileuploadkit/FileUpload.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/rap/rwt/internal/widgets/fileuploadkit/FileUpload.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/browser/browserkit/Browser.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/browser/browserkit/Browser.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/browser/browserkit/Browser.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/ccombokit/CCombo.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/ccombokit/CCombo.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/ccombokit/CCombo.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/clabelkit/CLabel.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/clabelkit/CLabel.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/clabelkit/CLabel.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/ctabfolderkit/CTabFolder.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/ctabfolderkit/CTabFolder.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/ctabfolderkit/CTabFolder.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/custom/scrolledcompositekit/ScrolledComposite.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/buttonkit/Button.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/buttonkit/Button.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/buttonkit/Button.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/combokit/Combo.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/combokit/Combo.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/combokit/Combo.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/compositekit/Composite.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/compositekit/Composite.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/compositekit/Composite.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/controlkit/Control.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/controlkit/Control.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/coolbarkit/CoolBar.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/coolbarkit/CoolBar.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/coolbarkit/CoolBar.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/datetimekit/DateTime.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/datetimekit/DateTime.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/datetimekit/DateTime.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/expandbarkit/ExpandBar.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/expandbarkit/ExpandBar.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/expandbarkit/ExpandBar.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/groupkit/Group.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/groupkit/Group.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/groupkit/Group.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/labelkit/Label.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/labelkit/Label.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/labelkit/Label.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/linkkit/Link.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/linkkit/Link.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/linkkit/Link.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/listkit/List.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/listkit/List.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/listkit/List.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/menukit/Menu.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/menukit/Menu.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/menukit/Menu.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/progressbarkit/ProgressBar.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/progressbarkit/ProgressBar.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/progressbarkit/ProgressBar.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/sashkit/Sash.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/sashkit/Sash.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/sashkit/Sash.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/scalekit/Scale.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/scalekit/Scale.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/scalekit/Scale.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/scrollbarkit/ScrollBar.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/scrollbarkit/ScrollBar.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/scrollbarkit/ScrollBar.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/shellkit/Shell.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/shellkit/Shell.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/shellkit/Shell.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/sliderkit/Slider.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/sliderkit/Slider.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/sliderkit/Slider.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/spinnerkit/Spinner.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/spinnerkit/Spinner.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/spinnerkit/Spinner.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tabfolderkit/TabFolder.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tabfolderkit/TabFolder.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tabfolderkit/TabFolder.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tablekit/Table.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tablekit/Table.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tablekit/Table.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/textkit/Text.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/textkit/Text.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/textkit/Text.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/toolbarkit/ToolBar.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/toolbarkit/ToolBar.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/toolbarkit/ToolBar.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tooltipkit/ToolTip.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tooltipkit/ToolTip.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/tooltipkit/ToolTip.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/treekit/Tree.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/treekit/Tree.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/treekit/Tree.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/widgetkit/Widget.appearances.js\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/widgetkit/Widget.default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/eclipse/swt/internal/widgets/widgetkit/Widget.theme.xml\\E"
-    }, 
-    {
-      "pattern":"\\Qorg/slf4j/impl/StaticLoggerBinder.class\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/static/html/blank.html\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/static/image/blank.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/theme/default.css\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/chevron-left-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/chevron-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/chevron-right-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/chevron-right.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/tooltip-down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/tooltip-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/tooltip-right.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/arrows/tooltip-up.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/arrow-down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/arrow-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/arrow-right.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/arrow-up.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/check-grayed-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/check-grayed.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/check-selected-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/check-selected.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/check-unselected-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/check-unselected.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/radio-selected-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/radio-selected.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/radio-unselected-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/button/radio-unselected.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/lastMonth-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/lastMonth.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/lastYear-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/lastYear.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/nextMonth-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/nextMonth.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/nextYear-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/calendar/nextYear.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ccombo/down-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ccombo/down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/column/sort-indicator-down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/column/sort-indicator-up.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/combo/down-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/combo/down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/close.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/close_hover.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/ctabfolder-dropdown-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/ctabfolder-dropdown-left-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/ctabfolder-dropdown-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/ctabfolder-dropdown.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/maximize.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/minimize.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/ctabfolder/restore.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/cursors/alias.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/cursors/copy.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/cursors/move.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/cursors/nodrop.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/cursors/up_arrow.cur\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/datetime/down-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/datetime/down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/datetime/up-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/datetime/up.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/dialog/error.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/dialog/information.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/dialog/question.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/dialog/warning.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/display/browser_bg.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/display/loading.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/expanditem/expanditem-collapse-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/expanditem/expanditem-collapse.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/expanditem/expanditem-expand-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/expanditem/expanditem-expand.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/menu/arrow-left.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/menu/arrow-right.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/menu/checkbox.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/menu/radiobutton.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/progressbar/progressbar-background.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/sash/sash-handle-horizontal.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/sash/sash-handle-vertical.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/scale/h_line.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/scale/v_line.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/scrollbar/down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/scrollbar/left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/scrollbar/right.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/scrollbar/scrollbar-background.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/scrollbar/up.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/slider/down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/slider/left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/slider/right.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/slider/slider-background.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/slider/up.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/spinner/down-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/spinner/down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/spinner/up-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/spinner/up.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/text/clear.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/text/find.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/toolbar/down.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tooltip/error.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tooltip/information.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tooltip/warning.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/loading.gif\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-collapsed-hover-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-collapsed-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-collapsed-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-collapsed.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-expanded-hover-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-expanded-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-expanded-left.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/tree/tree-expanded.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-close-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-close.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-max-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-max.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-min-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-min.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-restore-hover.png\\E"
-    }, 
-    {
-      "pattern":"\\Qresource/widget/rap/window/shell-restore.png\\E"
-    }
-  ]},
-  "bundles":[
-    {
-      "name":"javax.servlet.LocalStrings",
-      "locales":[""]
-    }, 
-    {
-      "name":"javax.servlet.http.LocalStrings",
-      "locales":[""]
-    }, 
-    {
-      "name":"org.apache.xerces.impl.xpath.regex.message",
-      "locales":[
-        "", 
-        "en"
-      ]
-    }, 
-    {
-      "name":"org.eclipse.rap.rwt.internal.RWTMessages",
-      "locales":[""]
-    }, 
-    {
-      "name":"sun.security.util.Resources",
-      "classNames":["sun.security.util.Resources"]
-    }
-  ]
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/serialization-config.json b/swt/rap/org.argeo.cms.swt.rap.cli/META-INF/native-image/serialization-config.json
deleted file mode 100644 (file)
index bf554e0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "types":[
-  ],
-  "lambdaCapturingTypes":[
-  ]
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/bnd.bnd b/swt/rap/org.argeo.cms.swt.rap.cli/bnd.bnd
deleted file mode 100644 (file)
index 4dce79b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-Import-Package: \
-org.eclipse.jetty.util.component;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.http;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.io;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.security;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.server.handler;version="[9.4,12)";resolution:=optional,\
-org.eclipse.jetty.*;version="[9.4,12)";resolution:=optional,\
-*
\ No newline at end of file
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/build.properties b/swt/rap/org.argeo.cms.swt.rap.cli/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/CmsRapCli.java b/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/CmsRapCli.java
deleted file mode 100644 (file)
index 5191b77..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.argeo.cms.swt.rap.cli;
-
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.argeo.api.acr.spi.ProvidedRepository;
-import org.argeo.api.cli.CommandsCli;
-import org.argeo.api.cli.DescribedCommand;
-import org.argeo.api.cms.CmsApp;
-import org.argeo.api.cms.CmsContext;
-import org.argeo.api.cms.CmsState;
-import org.argeo.cms.jetty.CmsJettyServer;
-import org.argeo.cms.runtime.StaticCms;
-import org.argeo.cms.swt.app.CmsUserApp;
-import org.argeo.cms.web.CmsWebApp;
-import org.argeo.util.register.Component;
-import org.argeo.util.register.ComponentRegister;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-
-public class CmsRapCli extends CommandsCli {
-
-       public CmsRapCli(String commandName) {
-               super(commandName);
-               addCommand("user", new Launch());
-       }
-
-       @Override
-       public String getDescription() {
-               return "Argeo CMS utilities.";
-       }
-
-       public static void main(String[] args) {
-               mainImpl(new CmsRapCli("web"), args);
-       }
-
-       static class Launch implements DescribedCommand<String> {
-               private Option dataOption;
-               private Option uiOption;
-
-               @Override
-               public Options getOptions() {
-                       Options options = new Options();
-                       dataOption = Option.builder().longOpt("data").hasArg().required()
-                                       .desc("path to the writable data area (mandatory)").build();
-                       uiOption = Option.builder().longOpt("ui").desc("open a user interface").build();
-                       options.addOption(dataOption);
-                       options.addOption(uiOption);
-                       return options;
-               }
-
-               @Override
-               public String apply(List<String> args) {
-                       CommandLine cl = toCommandLine(args);
-                       String dataPath = cl.getOptionValue(dataOption);
-                       boolean ui = cl.hasOption(uiOption);
-
-                       Path instancePath = Paths.get(dataPath);
-                       System.setProperty("osgi.instance.area", instancePath.toUri().toString());
-                       System.setProperty("argeo.http.port", "0");
-
-                       StaticCms staticCms = new StaticCms() {
-                               @Override
-                               protected void addComponents(ComponentRegister register) {
-                                       if (ui) {
-                                               CmsUserApp cmsApp = new CmsUserApp();
-                                               Component<CmsUserApp> cmsAppC = new Component.Builder<>(cmsApp) //
-                                                               .addType(CmsApp.class) //
-                                                               .addType(CmsUserApp.class) //
-                                                               .addDependency(register.getSingleton(CmsContext.class), cmsApp::setCmsContext, null) //
-                                                               .addDependency(register.getSingleton(ProvidedRepository.class),
-                                                                               cmsApp::setContentRepository, null) //
-                                                               .build(register);
-
-                                               CmsWebApp cmsWebApp = new CmsWebApp();
-                                               Component<CmsWebApp> cmsWebAppC = new Component.Builder<>(cmsWebApp) //
-                                                               .addType(ApplicationConfiguration.class) //
-                                                               .addType(CmsWebApp.class) //
-                                                               .addDependency(cmsAppC.getType(CmsApp.class), cmsWebApp::setCmsApp, null) //
-                                                               .build(register);
-
-                                               RapJettyServer rwtRunner = new RapJettyServer();
-                                               Component<RapJettyServer> rwtRunnerC = new Component.Builder<>(rwtRunner) //
-                                                               .addActivation(rwtRunner::start) //
-                                                               .addDeactivation(rwtRunner::stop) //
-                                                               .addType(CmsJettyServer.class) //
-                                                               .addDependency(register.getSingleton(CmsState.class), rwtRunner::setCmsState, null) //
-                                                               .addDependency(cmsWebAppC.getType(CmsWebApp.class), rwtRunner::setCmsWebApp, null) //
-                                                               .build(register);
-                                       }
-                               }
-
-                       };
-                       Runtime.getRuntime().addShutdownHook(new Thread(() -> staticCms.stop(), "Static CMS Shutdown"));
-                       staticCms.start();
-
-                       long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
-                       System.out.println("Static CMS available in " + jvmUptime + " ms.");
-
-                       if (ui) {
-                               try {
-                                       // open browser in app mode
-                                       Thread.sleep(2000);// wait for RWT to be ready
-                                       String browserCommand = "google-chrome --app=http://localhost:"
-                                                       + staticCms.getComponentRegister().getObject(CmsJettyServer.class).getHttpPort() + "/data";
-                                       Runtime.getRuntime().exec(browserCommand);
-                               } catch (InterruptedException | IOException e) {
-                                       e.printStackTrace();
-                               }
-                       }
-
-                       staticCms.waitForStop();
-
-                       return null;
-               }
-
-               @Override
-               public String getDescription() {
-                       return "Launch a static CMS.";
-               }
-
-       }
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RapJettyServer.java b/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RapJettyServer.java
deleted file mode 100644 (file)
index 5b3337a..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.argeo.cms.swt.rap.cli;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.ServletException;
-
-import org.argeo.cms.jetty.CmsJettyServer;
-import org.argeo.cms.web.CmsWebApp;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.rap.rwt.application.ApplicationRunner;
-import org.eclipse.rap.rwt.engine.RWTServlet;
-
-public class RapJettyServer extends CmsJettyServer {
-       private CmsWebApp cmsWebApp;
-
-       @Override
-       protected void addServlets(ServletContextHandler servletContextHandler) throws ServletException {
-               // rwt-resources requires a file system
-               try {
-                       Path tempDir = Files.createTempDirectory("argeo-rwtRunner");
-                       servletContextHandler.setBaseResource(Resource.newResource(tempDir.resolve("www").toString()));
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot create temporary directory", e);
-               }
-               servletContextHandler.addEventListener(new ServletContextListener() {
-                       ApplicationRunner applicationRunner;
-
-                       @Override
-                       public void contextInitialized(ServletContextEvent sce) {
-                               applicationRunner = new ApplicationRunner(cmsWebApp, sce.getServletContext());
-                               applicationRunner.start();
-                       }
-
-                       @Override
-                       public void contextDestroyed(ServletContextEvent sce) {
-                               applicationRunner.stop();
-                       }
-               });
-               for (String uiName : cmsWebApp.getCmsApp().getUiNames())
-                       servletContextHandler.addServlet(new ServletHolder(new RWTServlet()), "/" + uiName);
-
-               // Required to serve rwt-resources. It is important that this is last.
-               ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
-               servletContextHandler.addServlet(holderPwd, "/");
-
-       }
-
-       public void setCmsWebApp(CmsWebApp cmsWebApp) {
-               this.cmsWebApp = cmsWebApp;
-       }
-
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java b/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java
deleted file mode 100644 (file)
index b03939f..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-package org.argeo.cms.swt.rap.cli;
-
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Objects;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-import org.argeo.minidesktop.MiniDesktopManager;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.ApplicationRunner;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.engine.RWTServlet;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** A minimal RWT runner based on embedded Jetty. */
-public class RwtRunner {
-
-       private final Server server;
-       private final ServerConnector serverConnector;
-       private Path tempDir;
-
-       private ApplicationConfiguration applicationConfiguration;
-
-       public RwtRunner() {
-               server = new Server(new QueuedThreadPool(10, 1));
-               serverConnector = new ServerConnector(server);
-               serverConnector.setPort(0);
-               server.setConnectors(new Connector[] { serverConnector });
-       }
-
-       protected Control createUi(Composite parent, Object context) {
-               return new Label(parent, 0);
-       }
-
-       public void init() {
-               Objects.requireNonNull(applicationConfiguration);
-
-               ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
-               context.setContextPath("/");
-               server.setHandler(context);
-
-               String entryPoint = "app";
-
-               // rwt-resources requires a file system
-               try {
-                       tempDir = Files.createTempDirectory("argeo-rwtRunner");
-                       context.setBaseResource(Resource.newResource(tempDir.resolve("www").toString()));
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot create temporary directory", e);
-               }
-               context.addEventListener(new ServletContextListener() {
-                       ApplicationRunner applicationRunner;
-
-                       @Override
-                       public void contextInitialized(ServletContextEvent sce) {
-                               applicationRunner = new ApplicationRunner(applicationConfiguration, sce.getServletContext());
-                               applicationRunner.start();
-                       }
-
-                       @Override
-                       public void contextDestroyed(ServletContextEvent sce) {
-                               applicationRunner.stop();
-                       }
-               });
-
-               context.addServlet(new ServletHolder(new RWTServlet()), "/" + entryPoint);
-
-               // Required to serve rwt-resources. It is important that this is last.
-               ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
-               context.addServlet(holderPwd, "/");
-
-               try {
-                       server.start();
-               } catch (Exception e) {
-                       throw new IllegalStateException("Cannot start Jetty server", e);
-               }
-               Runtime.getRuntime().addShutdownHook(new Thread(() -> destroy(), "Jetty shutdown"));
-
-               long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
-               System.out.println("RWT App available in " + jvmUptime + " ms, on port " + getEffectivePort());
-       }
-
-       public void destroy() {
-               try {
-                       serverConnector.close();
-                       server.stop();
-                       // TODO delete temp dir
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-       }
-
-       public Integer getEffectivePort() {
-               return serverConnector.getLocalPort();
-       }
-
-       public void waitFor() throws InterruptedException {
-               server.join();
-       }
-
-       public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
-               this.applicationConfiguration = applicationConfiguration;
-       }
-
-       public static void main(String[] args) throws Exception {
-               RwtRunner rwtRunner = new RwtRunner();
-
-               String entryPoint = "app";
-               ApplicationConfiguration applicationConfiguration = (application) -> {
-                       application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
-                       application.addEntryPoint("/" + entryPoint, () -> new EntryPoint() {
-                               @Override
-                               public int createUI() {
-                                       MiniDesktopManager miniDesktopManager = new MiniDesktopManager(false, false);
-                                       miniDesktopManager.init();
-                                       miniDesktopManager.run();
-                                       return 0;
-                               }
-                       }, null);
-               };
-
-               rwtRunner.setApplicationConfiguration(applicationConfiguration);
-               rwtRunner.init();
-
-               // open browser in app mode
-               Thread.sleep(2000);// wait for RWT to be ready
-               Runtime.getRuntime().exec("google-chrome --app=http://localhost:" + rwtRunner.getEffectivePort() + "/app");
-
-               rwtRunner.waitFor();
-       }
-}
index 31555d168d10b1c2f8f1a44984014f20c458230a..67fa5ceac2b37efd000f18e5032ea6e2e63f948b 100644 (file)
@@ -12,7 +12,7 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.ux.CmsTheme;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.util.LangUtils;
+import org.argeo.cms.util.LangUtils;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.application.Application;
 import org.eclipse.rap.rwt.application.Application.OperationMode;
index d63aeeea53471ea6a62731daed32cb47129f7168..70f49f670054b82424104b68793fb1a190feaf30 100644 (file)
@@ -17,8 +17,8 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsSession;
 import org.argeo.api.cms.ux.CmsImageManager;
 import org.argeo.api.cms.ux.CmsView;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.LocaleUtils;
-import org.argeo.cms.auth.CurrentUser;
 import org.argeo.cms.auth.RemoteAuthCallbackHandler;
 import org.argeo.cms.servlet.ServletHttpRequest;
 import org.argeo.cms.servlet.ServletHttpResponse;
@@ -283,9 +283,9 @@ public class CmsWebEntryPoint extends AbstractSwtCmsView implements EntryPoint,
                                                }
                                        } else if (e instanceof ThreadDeath) {
                                                throw (ThreadDeath) e;
-                                       } else if (e instanceof Error) {
-                                               log.error("Unexpected error in event loop, shutting down...", e);
-                                               break eventLoop;
+//                                     } else if (e instanceof Error) {
+//                                             log.error("Unexpected error in event loop, shutting down...", e);
+//                                             break eventLoop;
                                        } else {
                                                log.error("Unexpected exception in event loop, ignoring it. " + e.getMessage());
                                                continue eventLoop;
index afaf71f983e6bdbdbf4065f1ebd6fd556c6887d8..6743a4e078d56f049ba9989f84c9bf0537c2fa10 100644 (file)
@@ -5,7 +5,7 @@
       <children xsi:type="advanced:Perspective" xmi:id="_oI_oICnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.perspective.cmsadmin" label="CMS Admin">
         <children xsi:type="basic:PartSashContainer" xmi:id="_qc16ECnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.partsashcontainer.0" horizontal="true">
           <children xsi:type="basic:PartStack" xmi:id="_RE87kDsXEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.rcp.partstack.1">
-            <children xsi:type="basic:Part" xmi:id="_V1WvgDsXEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.rcp.part.files" contributionURI="bundleclass://org.argeo.cms.e4/org.argeo.cms.e4.files.NodeFsBrowserView" label="Files"/>
+            <children xsi:type="basic:Part" xmi:id="_V1WvgDsXEeiUntFYWh-hFg" elementId="org.argeo.cms.e4.rcp.part.files" contributionURI="bundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.files.NodeFsBrowserView" label="Files"/>
             <children xsi:type="basic:Part" xmi:id="_vOqDQCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.part.jcr" containerData="4000" contributionURI="bundleclass://org.argeo.cms.jcr.e4/org.argeo.cms.e4.jcr.JcrBrowserView" label="JCR"/>
           </children>
           <children xsi:type="basic:PartStack" xmi:id="_0eRiwCnCEei1F8sdBz8Mpw" elementId="org.argeo.cms.e4.rcp.partstack.0" containerData="6000">
index ff79c8041156aa6010641c0b307ab5fe48c2a62c..eaa51adecead40031e25913a3356a96061456aa6 100644 (file)
@@ -4,4 +4,5 @@ Require-Bundle: org.eclipse.core.runtime
 
 Import-Package: !org.eclipse.core.runtime,\
 org.eclipse.swt,\
+org.eclipse.*;resolution:=optional,\
 *
index 16d3ca8d2ff57300e2a1d5e1459cac8b02321f4a..3861597aad00baa1b232366cc923d22e9fb45a60 100644 (file)
@@ -12,8 +12,7 @@ import org.argeo.api.cms.CmsAuth;
 import org.argeo.api.cms.ux.CmsImageManager;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.CurrentUser;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.SimpleSwtUxContext;
 import org.argeo.cms.swt.auth.CmsLoginShell;
@@ -156,7 +155,7 @@ public class CmsE4Application implements IApplication, CmsView {
        @Override
        public void authChange(LoginContext loginContext) {
                if (loginContext == null)
-                       throw new CmsException("Login context cannot be null");
+                       throw new IllegalStateException("Login context cannot be null");
                // logout previous login context
                // if (this.loginContext != null)
                // try {
@@ -170,12 +169,12 @@ public class CmsE4Application implements IApplication, CmsView {
        @Override
        public void logout() {
                if (loginContext == null)
-                       throw new CmsException("Login context should not bet null");
+                       throw new IllegalStateException("Login context should not bet null");
                try {
                        CurrentUser.logoutCmsSession(loginContext.getSubject());
                        loginContext.logout();
                } catch (LoginException e) {
-                       throw new CmsException("Cannot log out", e);
+                       throw new IllegalStateException("Cannot log out", e);
                }
        }
 
diff --git a/swt/rcp/org.argeo.cms.swt.rcp.cli/.classpath b/swt/rcp/org.argeo.cms.swt.rcp.cli/.classpath
deleted file mode 100644 (file)
index 81fe078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/swt/rcp/org.argeo.cms.swt.rcp.cli/.project b/swt/rcp/org.argeo.cms.swt.rcp.cli/.project
deleted file mode 100644 (file)
index 07c8c5d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.cms.swt.rcp.cli</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/swt/rcp/org.argeo.cms.swt.rcp.cli/bnd.bnd b/swt/rcp/org.argeo.cms.swt.rcp.cli/bnd.bnd
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/swt/rcp/org.argeo.cms.swt.rcp.cli/build.properties b/swt/rcp/org.argeo.cms.swt.rcp.cli/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/swt/rcp/org.argeo.cms.swt.rcp.cli/src/org/argeo/cms/swt/rcp/cli/CmsCli.java b/swt/rcp/org.argeo.cms.swt.rcp.cli/src/org/argeo/cms/swt/rcp/cli/CmsCli.java
deleted file mode 100644 (file)
index 3fe2935..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-package org.argeo.cms.swt.rcp.cli;
-
-import java.lang.management.ManagementFactory;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.concurrent.ForkJoinPool;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.argeo.api.acr.spi.ProvidedRepository;
-import org.argeo.api.cli.CommandsCli;
-import org.argeo.api.cli.DescribedCommand;
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.runtime.StaticCms;
-import org.argeo.cms.swt.app.CmsUserApp;
-import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
-import org.argeo.util.register.Component;
-import org.argeo.util.register.ComponentRegister;
-
-public class CmsCli extends CommandsCli {
-
-       public CmsCli(String commandName) {
-               super(commandName);
-               addCommand("static", new Launch());
-       }
-
-       @Override
-       public String getDescription() {
-               return "Argeo CMS utilities.";
-       }
-
-       static class Launch implements DescribedCommand<String> {
-               private Option dataOption;
-               private Option uiOption;
-
-               @Override
-               public Options getOptions() {
-                       Options options = new Options();
-                       dataOption = Option.builder().longOpt("data").hasArg().required()
-                                       .desc("path to the writable data area (mandatory)").build();
-                       uiOption = Option.builder().longOpt("ui").desc("open a user interface").build();
-                       options.addOption(dataOption);
-                       options.addOption(uiOption);
-                       return options;
-               }
-
-               @Override
-               public String apply(List<String> args) {
-                       CommandLine cl = toCommandLine(args);
-                       String dataPath = cl.getOptionValue(dataOption);
-                       boolean ui = cl.hasOption(uiOption);
-
-                       Path instancePath = Paths.get(dataPath);
-                       System.setProperty("osgi.instance.area", instancePath.toUri().toString());
-
-                       StaticCms staticCms = new StaticCms() {
-                               @Override
-                               protected void addComponents(ComponentRegister register) {
-                                       if (ui) {
-                                               Component<? extends ProvidedRepository> contentRepositoryC = register
-                                                               .find(ProvidedRepository.class, null).first();
-                                               CmsUserApp cmsApp = new CmsUserApp();
-                                               Component<CmsUserApp> cmsAppC = new Component.Builder<>(cmsApp) //
-                                                               .addType(CmsApp.class) //
-                                                               .addType(CmsUserApp.class) //
-                                                               .addDependency(contentRepositoryC.getType(ProvidedRepository.class),
-                                                                               cmsApp::setContentRepository, null) //
-                                                               .build(register);
-
-                                               CmsRcpDisplayFactory displayFactory = new CmsRcpDisplayFactory();
-                                               Component<CmsRcpDisplayFactory> displayFactoryC = new Component.Builder<>(displayFactory) //
-                                                               .addActivation(displayFactory::init) //
-                                                               .addDeactivation(displayFactory::destroy) //
-                                                               .build(register);
-
-                                       }
-                               }
-
-                               @Override
-                               protected void postActivation(ComponentRegister register) {
-                                       if (ui) {
-                                               Component<? extends CmsUserApp> cmsAppC = register.find(CmsUserApp.class, null).first();
-                                               CmsRcpDisplayFactory.openCmsApp(cmsAppC.get(), "data", (e) -> {
-                                                       // asynchronous in order to avoid deadlock in UI thread
-                                                       ForkJoinPool.commonPool().execute(() -> stop());
-                                               });
-                                       }
-                               }
-
-                       };
-                       Runtime.getRuntime().addShutdownHook(new Thread(() -> staticCms.stop(), "Static CMS Shutdown"));
-                       staticCms.start();
-
-                       long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
-                       System.out.println("Static CMS available in " + jvmUptime + " ms.");
-
-                       staticCms.waitForStop();
-
-                       return null;
-               }
-
-               @Override
-               public String getDescription() {
-                       return "Launch a static CMS.";
-               }
-
-       }
-}
index a0c0f0f5c0cd61777a0d99ac5fce663a2e6e7a0b..8b1d1468478f9a786ab3037ee89eaec06ad0a833 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Display Factory">
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="CMS RCP Display Factory">
    <implementation class="org.argeo.cms.ui.rcp.CmsRcpDisplayFactory"/>
 </scr:component>
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpHttpLauncher.xml b/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpHttpLauncher.xml
new file mode 100644 (file)
index 0000000..03abe19
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="true" name="CMS RCP Servlet Factory">
+   <implementation class="org.argeo.cms.ui.rcp.CmsRcpHttpLauncher"/>
+   <reference bind="setHttpServer" cardinality="1..1" interface="com.sun.net.httpserver.HttpServer" name="HttpServer" policy="static"/>
+   <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
+</scr:component>
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpServletFactory.xml b/swt/rcp/org.argeo.cms.swt.rcp/OSGI-INF/cmsRcpServletFactory.xml
deleted file mode 100644 (file)
index fe0bc64..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="CMS RCP Servlet Factory">
-   <implementation class="org.argeo.cms.ui.rcp.servlet.CmsRcpServletFactory"/>
-   <reference bind="addCmsApp" cardinality="0..n" interface="org.argeo.api.cms.CmsApp" name="CmsApp" policy="dynamic" unbind="removeCmsApp"/>
-   <reference bind="setHttpServer" cardinality="1..1" interface="com.sun.net.httpserver.HttpServer" name="HttpServer" policy="static"/>
-</scr:component>
index 91f0a8a3718eb5cb4d1a5140d6fe8bca8bc160f1..5cf5164e1b69f8c09156c2ee14ec4e29367405df 100644 (file)
@@ -1,3 +1,4 @@
+Bundle-SymbolicName: org.argeo.cms.swt.rcp;singleton=true
 
 Import-Package:\
 org.argeo.cms.auth,\
@@ -8,5 +9,5 @@ org.w3c.css.sac,\
 
 Service-Component:\
 OSGI-INF/cmsRcpDisplayFactory.xml,\
-OSGI-INF/cmsRcpServletFactory.xml
+OSGI-INF/cmsRcpHttpLauncher.xml
 
index 5eef7058e47f4318354d9b883628b2ce2723114c..4ed1d4748afc3e7dc121f8f0fab5a1c1a56d24e3 100644 (file)
@@ -2,5 +2,5 @@ output.. = bin/
 bin.includes = META-INF/,\
                .,\
                OSGI-INF/,\
-               OSGI-INF/cmsRcpServletFactory.xml
+               OSGI-INF/cmsRcpHttpLauncher.xml
 source.. = src/
index 950acceceb1f0edff1c764143e62b1b63babe3e9..a83a54db3926cfa2503079c22d3224dff28a8591 100644 (file)
@@ -1,14 +1,18 @@
 package org.argeo.cms.ui.rcp;
 
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
 import java.nio.file.Path;
 
 import org.argeo.api.cms.CmsApp;
-import org.argeo.util.OS;
+import org.argeo.cms.util.OS;
 import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.widgets.Display;
 
 /** Creates the SWT {@link Display} in a dedicated thread. */
 public class CmsRcpDisplayFactory {
+       private final static Logger logger = System.getLogger(CmsRcpDisplayFactory.class.getName());
+
        /** File name in a run directory */
        private final static String ARGEO_RCP_URL = "argeo.rcp.url";
 
@@ -50,20 +54,22 @@ public class CmsRcpDisplayFactory {
 
                @Override
                public void run() {
-                       display = Display.getDefault();
-                       display.setRuntimeExceptionHandler((e) -> e.printStackTrace());
-                       display.setErrorHandler((e) -> e.printStackTrace());
-
-//                     for (String contextName : cmsApps.keySet()) {
-//                             openCmsApp(contextName);
-//                     }
-
-                       while (!shutdown) {
-                               if (!display.readAndDispatch())
-                                       display.sleep();
+                       try {
+                               display = Display.getDefault();
+                               display.setRuntimeExceptionHandler((e) -> e.printStackTrace());
+                               display.setErrorHandler((e) -> e.printStackTrace());
+
+                               while (!shutdown) {
+                                       if (!display.readAndDispatch())
+                                               display.sleep();
+                               }
+                               display.dispose();
+                               display = null;
+                       } catch (UnsatisfiedLinkError e) {
+                               logger.log(Level.ERROR,
+                                               "Cannot load SWT, probably because the OSGi framework has been refresh. Restart the application.",
+                                               e);
                        }
-                       display.dispose();
-                       display = null;
                }
        }
 
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpHttpLauncher.java b/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/CmsRcpHttpLauncher.java
new file mode 100644 (file)
index 0000000..6246b0d
--- /dev/null
@@ -0,0 +1,128 @@
+package org.argeo.cms.ui.rcp;
+
+import static java.lang.System.Logger.Level.DEBUG;
+
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import org.argeo.api.cms.CmsApp;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+/** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
+public class CmsRcpHttpLauncher {
+       private final static Logger logger = System.getLogger(CmsRcpHttpLauncher.class.getName());
+       private CompletableFuture<HttpServer> httpServer = new CompletableFuture<>();
+
+       public void init() {
+
+       }
+
+       public void destroy() {
+               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
+               try {
+                       if (Files.exists(runFile)) {
+                               Files.delete(runFile);
+                       }
+               } catch (IOException e) {
+                       logger.log(Level.ERROR, "Cannot delete " + runFile, e);
+               }
+       }
+
+       public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+               final String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+               if (contextName != null) {
+                       httpServer.thenAcceptAsync((httpServer) -> {
+                               httpServer.createContext("/" + contextName, new HttpHandler() {
+
+                                       @Override
+                                       public void handle(HttpExchange exchange) throws IOException {
+                                               String path = exchange.getRequestURI().getPath();
+                                               String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
+                                               CmsRcpDisplayFactory.openCmsApp(cmsApp, uiName, null);
+                                               exchange.sendResponseHeaders(200, -1);
+                                               logger.log(Level.DEBUG, "Opened RCP UI  " + uiName + " of  CMS App /" + contextName);
+                                       }
+                               });
+                       }).exceptionally(e -> {
+                               logger.log(Level.ERROR, "Cannot register RCO app " + contextName, e);
+                               return null;
+                       });
+                       logger.log(Level.DEBUG, "Registered RCP CMS APP /" + contextName);
+               }
+       }
+
+       public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
+               String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
+               if (contextName != null) {
+                       httpServer.thenAcceptAsync((httpServer) -> {
+                               httpServer.removeContext("/" + contextName);
+                       });
+               }
+       }
+
+       public void setHttpServer(HttpServer httpServer) {
+               Integer httpPort = httpServer.getAddress().getPort();
+               String baseUrl = "http://localhost:" + httpPort + "/";
+               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
+               try {
+                       if (!Files.exists(runFile)) {
+                               Files.createDirectories(runFile.getParent());
+                               // TODO give read permission only to the owner
+                               Files.createFile(runFile);
+                       } else {
+                               URI uri = URI.create(Files.readString(runFile));
+                               if (!httpPort.equals(uri.getPort()))
+                                       if (!isPortAvailable(uri.getPort())) {
+                                               throw new IllegalStateException("Another CMS is running on " + runFile);
+                                       } else {
+                                               logger.log(Level.WARNING,
+                                                               "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
+                                       }
+                       }
+                       Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot write run file to " + runFile, e);
+               }
+               logger.log(DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
+               this.httpServer.complete(httpServer);
+       }
+
+       protected boolean isPortAvailable(int port) {
+               ServerSocket ss = null;
+               DatagramSocket ds = null;
+               try {
+                       ss = new ServerSocket(port);
+                       ss.setReuseAddress(true);
+                       ds = new DatagramSocket(port);
+                       ds.setReuseAddress(true);
+                       return true;
+               } catch (IOException e) {
+               } finally {
+                       if (ds != null) {
+                               ds.close();
+                       }
+
+                       if (ss != null) {
+                               try {
+                                       ss.close();
+                               } catch (IOException e) {
+                                       /* should not be thrown */
+                               }
+                       }
+               }
+
+               return false;
+       }
+}
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServlet.java b/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServlet.java
deleted file mode 100644 (file)
index 8579527..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.cms.ui.rcp.servlet;
-
-import java.io.IOException;
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.util.Objects;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
-
-/** Open the related app when called. */
-public class CmsRcpServlet extends HttpServlet {
-       private static final long serialVersionUID = -3944472431354848923L;
-       private final static Logger logger = System.getLogger(CmsRcpServlet.class.getName());
-
-       private CmsApp cmsApp;
-
-       public CmsRcpServlet(CmsApp cmsApp) {
-               Objects.requireNonNull(cmsApp);
-               this.cmsApp = cmsApp;
-       }
-
-       @Override
-       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-               String path = req.getPathInfo();
-               String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
-               CmsRcpDisplayFactory.openCmsApp(cmsApp, uiName, null);
-               logger.log(Level.DEBUG, "Opened RCP UI  " + uiName + " of  CMS App " + req.getServletPath());
-       }
-
-}
diff --git a/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServletFactory.java b/swt/rcp/org.argeo.cms.swt.rcp/src/org/argeo/cms/ui/rcp/servlet/CmsRcpServletFactory.java
deleted file mode 100644 (file)
index 09b1e41..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-package org.argeo.cms.ui.rcp.servlet;
-
-import static java.lang.System.Logger.Level.DEBUG;
-
-import java.io.IOException;
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.net.DatagramSocket;
-import java.net.ServerSocket;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Map;
-
-import org.argeo.api.cms.CmsApp;
-import org.argeo.cms.ui.rcp.CmsRcpDisplayFactory;
-
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
-
-/** Publishes one {@link CmsRcpServlet} per {@link CmsApp}. */
-public class CmsRcpServletFactory {
-       private final static Logger logger = System.getLogger(CmsRcpServletFactory.class.getName());
-       private HttpServer httpServer;
-//     private BundleContext bundleContext = FrameworkUtil.getBundle(CmsRcpServletFactory.class).getBundleContext();
-//
-//     private Map<String, ServiceRegistration<Servlet>> registrations = Collections.synchronizedMap(new HashMap<>());
-
-       public void init() {
-
-       }
-
-       public void destroy() {
-               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
-               try {
-                       if (Files.exists(runFile)) {
-                               Files.delete(runFile);
-                       }
-               } catch (IOException e) {
-                       logger.log(Level.ERROR, "Cannot delete " + runFile, e);
-               }
-       }
-
-       public void addCmsApp(CmsApp cmsApp, Map<String, String> properties) {
-               final String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
-               if (contextName != null) {
-                       httpServer.createContext("/" + contextName, new HttpHandler() {
-
-                               @Override
-                               public void handle(HttpExchange exchange) throws IOException {
-                                       String path = exchange.getRequestURI().getPath();
-                                       String uiName = path != null ? path.substring(path.lastIndexOf('/') + 1) : "";
-                                       CmsRcpDisplayFactory.openCmsApp(cmsApp, uiName, null);
-                                       exchange.sendResponseHeaders(200, -1);
-                                       logger.log(Level.DEBUG, "Opened RCP UI  " + uiName + " of  CMS App /" + contextName);
-                               }
-                       });
-                       logger.log(Level.DEBUG, "Registered RCP CMS APP /" + contextName);
-//                     CmsRcpServlet servlet = new CmsRcpServlet(cmsApp);
-//                     Hashtable<String, String> serviceProperties = new Hashtable<>();
-//                     serviceProperties.put("osgi.http.whiteboard.servlet.pattern", "/" + contextName + "/*");
-//                     ServiceRegistration<Servlet> sr = bundleContext.registerService(Servlet.class, servlet, serviceProperties);
-//                     registrations.put(contextName, sr);
-               }
-       }
-
-       public void removeCmsApp(CmsApp cmsApp, Map<String, String> properties) {
-               String contextName = properties.get(CmsApp.CONTEXT_NAME_PROPERTY);
-               if (contextName != null) {
-                       httpServer.removeContext("/" + contextName);
-//                     ServiceRegistration<Servlet> sr = registrations.get(contextName);
-//                     sr.unregister();
-               }
-       }
-
-       public void setHttpServer(HttpServer httpServer) {
-               this.httpServer = httpServer;
-               Integer httpPort = httpServer.getAddress().getPort();
-               String baseUrl = "http://localhost:" + httpPort + "/";
-               Path runFile = CmsRcpDisplayFactory.getUrlRunFile();
-               try {
-                       if (!Files.exists(runFile)) {
-                               Files.createDirectories(runFile.getParent());
-                               // TODO give read permission only to the owner
-                               Files.createFile(runFile);
-                       } else {
-                               URI uri = URI.create(Files.readString(runFile));
-                               if (!httpPort.equals(uri.getPort()))
-                                       if (!isPortAvailable(uri.getPort())) {
-                                               throw new IllegalStateException("Another CMS is running on " + runFile);
-                                       } else {
-                                               logger.log(Level.WARNING,
-                                                               "Run file " + runFile + " found but port of " + uri + " is available. Overwriting...");
-                                       }
-                       }
-                       Files.writeString(runFile, baseUrl, StandardCharsets.UTF_8);
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot write run file to " + runFile, e);
-               }
-               logger.log(DEBUG, "RCP available under " + baseUrl + ", written to " + runFile);
-       }
-
-       protected boolean isPortAvailable(int port) {
-               ServerSocket ss = null;
-               DatagramSocket ds = null;
-               try {
-                       ss = new ServerSocket(port);
-                       ss.setReuseAddress(true);
-                       ds = new DatagramSocket(port);
-                       ds.setReuseAddress(true);
-                       return true;
-               } catch (IOException e) {
-               } finally {
-                       if (ds != null) {
-                               ds.close();
-                       }
-
-                       if (ss != null) {
-                               try {
-                                       ss.close();
-                               } catch (IOException e) {
-                                       /* should not be thrown */
-                               }
-                       }
-               }
-
-               return false;
-       }
-}
index 91109a9de436d38789ce52fd6ad3a4cf9806df0c..47ff35dc0e13ac6a6ac70f8482332c80445b873f 100644 (file)
@@ -7,17 +7,16 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.TreeMap;
 
-import org.apache.commons.io.IOUtils;
+import org.argeo.cms.util.StreamUtils;
 import org.eclipse.rap.rwt.service.ResourceManager;
 
 public class RcpResourceManager implements ResourceManager {
-       private Map<String, byte[]> register = Collections
-                       .synchronizedMap(new TreeMap<String, byte[]>());
+       private Map<String, byte[]> register = Collections.synchronizedMap(new TreeMap<String, byte[]>());
 
        @Override
        public void register(String name, InputStream in) {
                try {
-                       register.put(name, IOUtils.toByteArray(in));
+                       register.put(name, StreamUtils.toByteArray(in));
                } catch (IOException e) {
                        throw new RuntimeException("Cannot register " + name, e);
                }