summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlberto Ruiz <alberto.ruiz@sun.com>2007-10-30 17:09:02 +0000
committerAlberto Ruiz <alberto.ruiz@sun.com>2007-10-30 17:09:02 +0000
commitd88cdbaac98eacbe86ea8d0a6aac79922f811912 (patch)
tree5223c0de0b64c377a07f44a4509386a99bdd5262
2007-30-10 Alberto Ruiz <alberto.ruiz@sun.com>
* Initial commit.
-rw-r--r--AUTHORS0
-rw-r--r--COPYING680
-rw-r--r--ChangeLog2
-rw-r--r--INSTALL229
-rw-r--r--Makefile.am8
-rw-r--r--NEWS0
-rw-r--r--README0
-rwxr-xr-xautogen.sh73
-rw-r--r--configure.ac62
-rw-r--r--m4/ac_check_class.m4107
-rw-r--r--m4/ac_check_classpath.m423
-rw-r--r--m4/ac_check_junit.m454
-rw-r--r--m4/ac_check_rqrd_class.m426
-rw-r--r--m4/ac_expand.m48
-rw-r--r--m4/ac_java_options.m432
-rw-r--r--m4/ac_prog_jar.m436
-rw-r--r--m4/ac_prog_java.m479
-rw-r--r--m4/ac_prog_java_works.m497
-rw-r--r--m4/ac_prog_javac.m443
-rw-r--r--m4/ac_prog_javac_works.m435
-rw-r--r--m4/ac_prog_javadoc.m437
-rw-r--r--m4/ac_prog_javah.m426
-rw-r--r--m4/ac_try_compile_java.m439
-rw-r--r--m4/ac_try_run_javac.m440
-rw-r--r--src/Makefile.am1
-rw-r--r--src/com/Makefile.am1
-rw-r--r--src/com/sun/Makefile.am1
-rw-r--r--src/com/sun/apoc/Makefile.am1
-rw-r--r--src/com/sun/apoc/spi/AbstractAssignmentProvider.java225
-rw-r--r--src/com/sun/apoc/spi/AssignmentProvider.java107
-rw-r--r--src/com/sun/apoc/spi/AuthenticationException.java71
-rw-r--r--src/com/sun/apoc/spi/CloseConnectionException.java50
-rw-r--r--src/com/sun/apoc/spi/ConnectionException.java63
-rw-r--r--src/com/sun/apoc/spi/ConnectionSizeLimitException.java51
-rw-r--r--src/com/sun/apoc/spi/IllegalAccessException.java46
-rw-r--r--src/com/sun/apoc/spi/IllegalAssignmentException.java60
-rw-r--r--src/com/sun/apoc/spi/IllegalReadException.java77
-rw-r--r--src/com/sun/apoc/spi/IllegalWriteException.java68
-rw-r--r--src/com/sun/apoc/spi/InterruptedConnectionException.java50
-rw-r--r--src/com/sun/apoc/spi/Makefile.am7
-rw-r--r--src/com/sun/apoc/spi/OpenConnectionException.java50
-rw-r--r--src/com/sun/apoc/spi/PolicyManager.java274
-rw-r--r--src/com/sun/apoc/spi/PolicySource.java297
-rw-r--r--src/com/sun/apoc/spi/Provider.java61
-rw-r--r--src/com/sun/apoc/spi/ProviderLoadingException.java52
-rw-r--r--src/com/sun/apoc/spi/SPIException.java369
-rw-r--r--src/com/sun/apoc/spi/build.xml.in181
-rw-r--r--src/com/sun/apoc/spi/cfgtree/ConfigElementImpl.java310
-rw-r--r--src/com/sun/apoc/spi/cfgtree/DataType.java232
-rw-r--r--src/com/sun/apoc/spi/cfgtree/ElementCopyException.java60
-rw-r--r--src/com/sun/apoc/spi/cfgtree/InvalidDataTypeException.java63
-rw-r--r--src/com/sun/apoc/spi/cfgtree/MandatoryElementException.java72
-rw-r--r--src/com/sun/apoc/spi/cfgtree/NodeKey.java52
-rw-r--r--src/com/sun/apoc/spi/cfgtree/NodeParsing.java476
-rw-r--r--src/com/sun/apoc/spi/cfgtree/NodeValueImpl.java557
-rw-r--r--src/com/sun/apoc/spi/cfgtree/OperationType.java104
-rw-r--r--src/com/sun/apoc/spi/cfgtree/PolicyTree.java123
-rw-r--r--src/com/sun/apoc/spi/cfgtree/PolicyTreeConverter.java60
-rw-r--r--src/com/sun/apoc/spi/cfgtree/PolicyTreeException.java48
-rw-r--r--src/com/sun/apoc/spi/cfgtree/PolicyTreeFactory.java72
-rw-r--r--src/com/sun/apoc/spi/cfgtree/PolicyTreeFactoryImpl.java109
-rw-r--r--src/com/sun/apoc/spi/cfgtree/PolicyTreeImpl.java286
-rw-r--r--src/com/sun/apoc/spi/cfgtree/ProtectedElement.java71
-rw-r--r--src/com/sun/apoc/spi/cfgtree/ProtectedElementImpl.java137
-rw-r--r--src/com/sun/apoc/spi/cfgtree/ReadOnlyElementException.java60
-rw-r--r--src/com/sun/apoc/spi/cfgtree/ReadWritePolicyTreeFactory.java60
-rw-r--r--src/com/sun/apoc/spi/cfgtree/XMLPolicyTreeException.java51
-rw-r--r--src/com/sun/apoc/spi/cfgtree/XMLStreamable.java63
-rw-r--r--src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeException.java60
-rw-r--r--src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeNameException.java56
-rw-r--r--src/com/sun/apoc/spi/cfgtree/policynode/MergedPolicyNode.java64
-rw-r--r--src/com/sun/apoc/spi/cfgtree/policynode/PolicyNode.java147
-rw-r--r--src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeException.java41
-rw-r--r--src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeImpl.java1124
-rw-r--r--src/com/sun/apoc/spi/cfgtree/policynode/ReadWritePolicyNodeImpl.java1059
-rw-r--r--src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyException.java67
-rw-r--r--src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyNameException.java56
-rw-r--r--src/com/sun/apoc/spi/cfgtree/property/MergedProperty.java73
-rw-r--r--src/com/sun/apoc/spi/cfgtree/property/Property.java279
-rw-r--r--src/com/sun/apoc/spi/cfgtree/property/PropertyException.java48
-rw-r--r--src/com/sun/apoc/spi/cfgtree/property/PropertyImpl.java1192
-rw-r--r--src/com/sun/apoc/spi/cfgtree/property/ReadWritePropertyImpl.java967
-rw-r--r--src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeConverterImpl.java124
-rw-r--r--src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeFactoryImpl.java115
-rw-r--r--src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeImpl.java396
-rw-r--r--src/com/sun/apoc/spi/copyright.txt3
-rw-r--r--src/com/sun/apoc/spi/entities/AbstractEntity.java214
-rw-r--r--src/com/sun/apoc/spi/entities/Domain.java84
-rw-r--r--src/com/sun/apoc/spi/entities/DomainTreeProvider.java53
-rw-r--r--src/com/sun/apoc/spi/entities/Entity.java149
-rw-r--r--src/com/sun/apoc/spi/entities/EntityException.java45
-rw-r--r--src/com/sun/apoc/spi/entities/EntityTreeProvider.java62
-rw-r--r--src/com/sun/apoc/spi/entities/Host.java46
-rw-r--r--src/com/sun/apoc/spi/entities/InvalidEntityIdException.java39
-rw-r--r--src/com/sun/apoc/spi/entities/InvalidFilterException.java55
-rw-r--r--src/com/sun/apoc/spi/entities/Leaf.java54
-rw-r--r--src/com/sun/apoc/spi/entities/NoSuchEntityException.java56
-rw-r--r--src/com/sun/apoc/spi/entities/Node.java139
-rw-r--r--src/com/sun/apoc/spi/entities/Organization.java84
-rw-r--r--src/com/sun/apoc/spi/entities/OrganizationTreeProvider.java53
-rw-r--r--src/com/sun/apoc/spi/entities/Role.java92
-rw-r--r--src/com/sun/apoc/spi/entities/User.java65
-rw-r--r--src/com/sun/apoc/spi/environment/ConfigurationProvider.java45
-rw-r--r--src/com/sun/apoc/spi/environment/EnvironmentConstants.java195
-rw-r--r--src/com/sun/apoc/spi/environment/EnvironmentException.java55
-rw-r--r--src/com/sun/apoc/spi/environment/EnvironmentMgr.java726
-rw-r--r--src/com/sun/apoc/spi/environment/InvalidParameterException.java71
-rw-r--r--src/com/sun/apoc/spi/environment/MissingParameterException.java63
-rw-r--r--src/com/sun/apoc/spi/environment/ParameterException.java68
-rw-r--r--src/com/sun/apoc/spi/environment/RemoteEnvironmentException.java63
-rw-r--r--src/com/sun/apoc/spi/file/FileProviderFactory.java84
-rw-r--r--src/com/sun/apoc/spi/file/assignments/FileAssignmentProvider.java334
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileDomain.java190
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileDomainProvider.java175
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileEntity.java113
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileEntityProvider.java178
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileHost.java66
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileNode.java254
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileOrganization.java191
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileOrganizationProvider.java193
-rw-r--r--src/com/sun/apoc/spi/file/entities/FileUser.java85
-rw-r--r--src/com/sun/apoc/spi/file/environment/FileConfigurationProvider.java108
-rw-r--r--src/com/sun/apoc/spi/file/profiles/FileProfile.java644
-rw-r--r--src/com/sun/apoc/spi/file/profiles/FileProfileComparator.java86
-rw-r--r--src/com/sun/apoc/spi/file/profiles/FileProfileProvider.java343
-rw-r--r--src/com/sun/apoc/spi/file/profiles/FileProfileRepository.java351
-rw-r--r--src/com/sun/apoc/spi/ldap/LdapAssignmentProvider.java191
-rw-r--r--src/com/sun/apoc/spi/ldap/LdapClientContext.java426
-rw-r--r--src/com/sun/apoc/spi/ldap/LdapConnectionHandler.java310
-rw-r--r--src/com/sun/apoc/spi/ldap/LdapConnectionPool.java79
-rw-r--r--src/com/sun/apoc/spi/ldap/LdapProviderFactory.java82
-rw-r--r--src/com/sun/apoc/spi/ldap/authentication/LdapSaslGSSAPICallback.java47
-rw-r--r--src/com/sun/apoc/spi/ldap/authentication/SaslFactory.java63
-rw-r--r--src/com/sun/apoc/spi/ldap/authentication/SaslGSSAPICallback.java73
-rw-r--r--src/com/sun/apoc/spi/ldap/authentication/SaslMechanism.java118
-rw-r--r--src/com/sun/apoc/spi/ldap/datastore/LdapDataStore.java3339
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapDomain.java798
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapDomainProvider.java99
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapEntity.java524
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapEntityProvider.java111
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapEntityType.java130
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapHost.java183
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapNode.java1283
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapOrganization.java817
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapOrganizationProvider.java99
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapRole.java500
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/LdapUser.java268
-rw-r--r--src/com/sun/apoc/spi/ldap/entities/mapping/LdapEntityMapping.java205
-rw-r--r--src/com/sun/apoc/spi/ldap/environment/LdapConfigurationProvider.java165
-rw-r--r--src/com/sun/apoc/spi/ldap/environment/LdapEnvironmentMgr.java627
-rw-r--r--src/com/sun/apoc/spi/ldap/policies/LdapPolicy.java167
-rw-r--r--src/com/sun/apoc/spi/ldap/profiles/LdapProfile.java545
-rw-r--r--src/com/sun/apoc/spi/ldap/profiles/LdapProfileComparator.java78
-rw-r--r--src/com/sun/apoc/spi/ldap/profiles/LdapProfileProvider.java204
-rw-r--r--src/com/sun/apoc/spi/ldap/profiles/LdapProfileRepository.java305
-rw-r--r--src/com/sun/apoc/spi/ldap/profiles/LdapUserProfile.java356
-rw-r--r--src/com/sun/apoc/spi/ldap/util/Timestamp.java96
-rw-r--r--src/com/sun/apoc/spi/memory/AssignmentProviderImpl.java107
-rw-r--r--src/com/sun/apoc/spi/memory/entities/DomainImpl.java64
-rw-r--r--src/com/sun/apoc/spi/memory/entities/EntityImpl.java113
-rw-r--r--src/com/sun/apoc/spi/memory/entities/EntityNodeImpl.java108
-rw-r--r--src/com/sun/apoc/spi/memory/entities/EntityProviderImpl.java144
-rw-r--r--src/com/sun/apoc/spi/memory/entities/HostImpl.java55
-rw-r--r--src/com/sun/apoc/spi/memory/entities/OrganizationImpl.java64
-rw-r--r--src/com/sun/apoc/spi/memory/entities/UserImpl.java66
-rw-r--r--src/com/sun/apoc/spi/memory/profiles/ProfileImpl.java182
-rw-r--r--src/com/sun/apoc/spi/memory/profiles/ProfileProviderImpl.java153
-rw-r--r--src/com/sun/apoc/spi/memory/profiles/ProfileRepositoryImpl.java106
-rw-r--r--src/com/sun/apoc/spi/policies/InvalidPolicyException.java54
-rw-r--r--src/com/sun/apoc/spi/policies/MismatchPolicyException.java48
-rw-r--r--src/com/sun/apoc/spi/policies/NoSuchPolicyException.java56
-rw-r--r--src/com/sun/apoc/spi/policies/Policy.java110
-rw-r--r--src/com/sun/apoc/spi/policies/PolicyException.java45
-rw-r--r--src/com/sun/apoc/spi/policies/PolicyInfo.java110
-rw-r--r--src/com/sun/apoc/spi/profiles/Applicability.java129
-rw-r--r--src/com/sun/apoc/spi/profiles/InvalidDisplayNameException.java66
-rw-r--r--src/com/sun/apoc/spi/profiles/InvalidPriorityException.java58
-rw-r--r--src/com/sun/apoc/spi/profiles/InvalidProfileException.java72
-rw-r--r--src/com/sun/apoc/spi/profiles/NullProfileException.java46
-rw-r--r--src/com/sun/apoc/spi/profiles/Profile.java235
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileComparatorProvider.java50
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileException.java47
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileImpl.java283
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileProvider.java93
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileRepository.java156
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileRepositoryImpl.java263
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileStreamException.java60
-rw-r--r--src/com/sun/apoc/spi/profiles/ProfileZipException.java52
-rw-r--r--src/com/sun/apoc/spi/profiles/UnknownApplicabilityException.java48
-rw-r--r--src/com/sun/apoc/spi/profiles/ZipProfileReadWrite.java282
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors.properties135
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_de.properties134
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_en.properties135
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_en_US.properties135
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_es.properties134
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_fr.properties134
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_ja.properties134
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_ko.properties134
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_zh_CN.properties134
-rw-r--r--src/com/sun/apoc/spi/resources/SPIErrors_zh_TW.properties134
-rw-r--r--src/com/sun/apoc/spi/util/BooleanReturnValue.java53
-rw-r--r--src/com/sun/apoc/spi/util/ImporterExporter.java78
-rw-r--r--src/com/sun/apoc/spi/util/MetaConfiguration.java258
-rw-r--r--src/com/sun/apoc/spi/util/StringEnum.java79
-rw-r--r--src/com/sun/apoc/spi/util/StringRangeEnum.java86
-rw-r--r--src/com/sun/apoc/spi/util/ZipImporterExporter.java200
206 files changed, 36717 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/AUTHORS
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..b8a9e57
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,680 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+1. Definitions.
+
+1.1. Contributor means each individual or entity that creates or
+contributes to the creation of Modifications.
+
+1.2. Contributor Version means the combination of the Original
+Software, prior Modifications used by a Contributor (if any),
+and the Modifications made by that particular Contributor.
+
+1.3. Covered Software means (a) the Original Software, or (b)
+Modifications, or (c) the combination of files containing
+Original Software with files containing Modifications, in each
+case including portions thereof.
+
+1.4. Executable means the Covered Software in any form other
+than Source Code.
+
+1.5. Initial Developer means the individual or entity that first
+makes Original Software available under this License.
+
+1.6. Larger Workmeans a work which combines Covered Software or
+portions thereof with code not governed by the terms of this
+License.
+
+1.7. License means this document.
+
+1.8. Licensable means having the right to grant, to the maximum
+extent possible, whether at the time of the initial grant or
+subsequently acquired, any and all of the rights conveyed herein.
+
+1.9. Modifications means the Source Code and Executable form of
+any of the following: A. Any file that results from an addition
+to, deletion from or modification of the contents of a file
+containing Original Software or previous Modifications; B. Any
+new file that contains any part of the Original Software or
+previous Modification; or C. Any new file that is contributed or
+otherwise made available under the terms of this License.
+
+1.10. Original Software means the Source Code and Executable
+form of computer software code that is originally released under
+this License.
+
+1.11. Patent Claims means any patent claim(s), now owned or
+hereafter acquired, including without limitation, method,
+process, and apparatus claims, in any patent Licensable by
+grantor.
+
+1.12. Source Code means (a) the common form of computer software
+code in which modifications are made and (b) associated
+documentation included in or with such code.
+
+1.13. You (or Your) means an individual or a legal entity
+exercising rights under, and complying with all of the terms of,
+this License. For legal entities, You includes any entity which
+controls, is controlled by, or is under common control with You.
+For purposes of this definition, control means (a) the power,
+direct or indirect, to cause the direction or management of such
+entity, whether by contract or otherwise, or (b) ownership of
+more than fifty percent (50%) of the outstanding shares or
+beneficial ownership of such entity.
+
+2. License Grants.
+
+2.1. The Initial Developer Grant. Conditioned upon Your
+compliance with Section 3.1 below and subject to third party
+intellectual property claims, the Initial Developer hereby
+grants You a world-wide, royalty-free, non-exclusive license:
+
+(a) under intellectual property rights (other than patent or
+trademark) Licensable by Initial Developer, to use, reproduce,
+modify, display, perform, sublicense and distribute the Original
+Software (or portions thereof), with or without Modifications,
+and/or as part of a Larger Work; and
+
+(b) under Patent Claims infringed by the making, using or
+selling of Original Software, to make, have made, use, practice,
+sell, and offer for sale, and/or otherwise dispose of the
+Original Software (or portions thereof);
+
+(c) The licenses granted in Sections 2.1(a) and (b) are
+effective on the date Initial Developer first distributes or
+otherwise makes the Original Software available to a third party
+under the terms of this License;
+
+(d) Notwithstanding Section 2.1(b) above, no patent license is
+granted: (1) for code that You delete from the Original
+Software, or (2) for infringements caused by: (i) the
+modification of the Original Software, or (ii) the combination
+of the Original Software with other software or devices.
+
+2.2. Contributor Grant. Conditioned upon Your compliance with
+Section 3.1 below and subject to third party intellectual
+property claims, each Contributor hereby grants You a
+world-wide, royalty-free, non-exclusive license:
+
+(a) under intellectual property rights (other than patent or
+trademark) Licensable by Contributor to use, reproduce, modify,
+display, perform, sublicense and distribute the Modifications
+created by such Contributor (or portions thereof), either on an
+unmodified basis, with other Modifications, as Covered Software
+and/or as part of a Larger Work; and
+
+(b) under Patent Claims infringed by the making, using, or
+selling of Modifications made by that Contributor either alone
+and/or in combination with its Contributor Version (or portions
+of such combination), to make, use, sell, offer for sale, have
+made, and/or otherwise dispose of: (1) Modifications made by
+that Contributor (or portions thereof); and (2) the combination
+of Modifications made by that Contributor with its Contributor
+Version (or portions of such combination).
+
+(c) The licenses granted in Sections 2.2(a) and 2.2(b)
+areeffective on the date Contributor first distributes or
+otherwise makes the Modifications available to a third party.
+
+(d) Notwithstanding Section 2.2(b) above, no patent license is
+granted: (1) for any code that Contributor has deleted from the
+Contributor Version; (2) for infringements caused by: (i) third
+party modifications of Contributor Version, or (ii) the
+combination of Modifications made by that Contributor with other
+software (except as part of the Contributor Version) or other
+devices; or (3) under Patent Claims infringed by Covered
+Software in the absence of Modifications made by that
+Contributor.
+
+3. Distribution Obligations.
+
+3.1. Availability of Source Code. Any Covered Software that You
+distribute or otherwise make available in Executable form must
+also be made available in Source Code form and that Source Code
+form must be distributed only under the terms of this License.
+You must include a copy of this License with every copy of the
+Source Code form of the Covered Software You distribute or
+otherwise make available. You must inform recipients of any such
+Covered Software in Executable form as to how they can obtain
+such Covered Software in Source Code form in a reasonable manner
+on or through a medium customarily used for software exchange.
+
+3.2. Modifications. The Modifications that You create or to
+which You contribute are governed by the terms of this License.
+You represent that You believe Your Modifications are Your
+original creation(s) and/or You have sufficient rights to grant
+the rights conveyed by this License.
+
+3.3. Required Notices. You must include a notice in each of Your
+Modifications that identifies You as the Contributor of the
+Modification. You may not remove or alter any copyright, patent
+or trademark notices contained within the Covered Software, or
+any notices of licensing or any descriptive text giving
+attribution to any Contributor or the Initial Developer.
+
+3.4. Application of Additional Terms. You may not offer or
+impose any terms on any Covered Software in Source Code form
+that alters or restricts the applicable version of this License
+or the recipients rights hereunder. You may choose to offer, and
+to charge a fee for, warranty, support, indemnity or liability
+obligations to one or more recipients of Covered
+Software. However, you may do so only on Your own behalf, and
+not on behalf of the Initial Developer or any Contributor. You
+must make it absolutely clear that any such warranty, support,
+indemnity or liability obligation is offered by You alone, and
+You hereby agree to indemnify the Initial Developer and every
+Contributor for any liability incurred by the Initial Developer
+or such Contributor as a result of warranty, support, indemnity
+or liability terms You offer.
+
+3.5. Distribution of Executable Versions. You may distribute the
+Executable form of the Covered Software under the terms of this
+License or under the terms of a license of Your choice, which
+may contain terms different from this License, provided that You
+are in compliance with the terms of this License and that the
+license for the Executable form does not attempt to limit or
+alter the recipients rights in the Source Code form from the
+rights set forth in this License. If You distribute the Covered
+Software in Executable form under a different license, You must
+make it absolutely clear that any terms which differ from this
+License are offered by You alone, not by the Initial Developer
+or Contributor. You hereby agree to indemnify the Initial
+Developer and every Contributor for any liability incurred by
+the Initial Developer or such Contributor as a result of any
+such terms You offer.
+
+3.6. Larger Works. You may create a Larger Work by combining
+Covered Software with other code not governed by the terms of
+this License and distribute the Larger Work as a single product.
+In such a case, You must make sure the requirements of this
+License are fulfilled for the Covered Software.
+
+4. Versions of the License.
+
+4.1. New Versions. Sun Microsystems, Inc. is the initial license
+steward and may publish revised and/or new versions of this
+License from time to time. Each version will be given a
+distinguishing version number. Except as provided in Section
+4.3, no one other than the license steward has the right to
+modify this License.
+
+4.2. Effect of New Versions. You may always continue to use,
+distribute or otherwise make the Covered Software available
+under the terms of the version of the License under which You
+originally received the Covered Software. If the Initial
+Developer includes a notice in the Original Software prohibiting
+it from being distributed or otherwise made available under any
+subsequent version of the License, You must distribute and make
+the Covered Software available under the terms of the version of
+the License under which You originally received the Covered
+Software. Otherwise, You may also choose to use, distribute or
+otherwise make the Covered Software available under the terms of
+any subsequent version of the License published by the license
+steward.
+
+4.3. Modified Versions. When You are an Initial Developer and
+You want to create a new license for Your Original Software, You
+may create and use a modified version of this License if You:
+(a) rename the license and remove any references to the name of
+the license steward (except to note that the license differs
+from this License); and (b) otherwise make it clear that the
+license contains terms which differ from this License.
+
+5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER
+THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
+WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS,
+MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
+SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE
+DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY
+OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING,
+REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
+ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE
+IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+6.1. This License and the rights granted hereunder will
+terminate automatically if You fail to comply with terms herein
+and fail to cure such breach within 30 days of becoming aware of
+the breach. Provisions which, by their nature, must remain in
+effect beyond the termination of this License shall survive.
+
+6.2. If You assert a patent infringement claim (excluding
+declaratory judgment actions) against Initial Developer or a
+Contributor (the Initial Developer or Contributor against whom
+You assert such claim is referred to as Participant) alleging
+that the Participant Software (meaning the Contributor Version
+where the Participant is a Contributor or the Original Software
+where the Participant is the Initial Developer) directly or
+indirectly infringes any patent, then any and all rights granted
+directly or indirectly to You by such Participant, the Initial
+Developer (if the Initial Developer is not the Participant) and
+all Contributors under Sections 2.1 and/or 2.2 of this License
+shall, upon 60 days notice from Participant terminate
+prospectively and automatically at the expiration of such 60 day
+notice period, unless if within such 60 day period You withdraw
+Your claim with respect to the Participant Software against such
+Participant either unilaterally or pursuant to a written
+agreement with Participant.
+
+6.3. In the event of termination under Sections 6.1 or 6.2
+above, all end user licenses that have been validly granted by
+You or any distributor hereunder prior to termination (excluding
+licenses granted to You by any distributor) shall survive
+termination.
+
+7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO
+LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR
+OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER
+CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY
+SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY
+INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST
+PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
+MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES,
+EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY
+OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO
+LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
+PARTYS NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
+LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
+LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS
+EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS. The Covered Software is a
+commercial item, as that term is defined in 48 C.F.R. 2.101
+(Oct. 1995), consisting of commercial computer software (as that
+term is defined at 48 C.F.R. 252.227-7014(a)(1)) and commercial
+computer software documentation as such terms are used in 48
+C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and
+48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+U.S. Government End Users acquire Covered Software with only
+those rights set forth herein. This U.S. Government Rights
+clause is in lieu of, and supersedes, any other FAR, DFAR, or
+other clause or provision that addresses Government rights in
+computer software under this License.
+
+9. MISCELLANEOUS. This License represents the complete agreement
+concerning subject matter hereof. If any provision of this
+License is held to be unenforceable, such provision shall be
+reformed only to the extent necessary to make it enforceable.
+This License shall be governed by the law of the jurisdiction
+specified in a notice contained within the Original Software
+(except to the extent applicable law, if any, provides
+otherwise), excluding such jurisdictions conflict-of-law
+provisions. Any litigation relating to this License shall be
+subject to the jurisdiction of the courts located in the
+jurisdiction and venue specified in a notice contained within
+the Original Software, with the losing party responsible for
+costs, including, without limitation, court costs and reasonable
+attorneys fees and expenses. The application of the United
+Nations Convention on Contracts for the International Sale of
+Goods is expressly excluded. Any law or regulation which
+provides that the language of a contract shall be construed
+against the drafter shall not apply to this License. You agree
+that You alone are responsible for compliance with the United
+States export administration regulations (and the export control
+laws and regulation of any other countries) when You use,
+distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and
+the Contributors, each party is responsible for claims and
+damages arising, directly or indirectly, out of its utilization
+of rights under this License and You agree to work with Initial
+Developer and Contributors to distribute such responsibility on
+an equitable basis. Nothing herein is intended or shall be
+deemed to constitute any admission of liability.
+
+----------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL): This code is released under the
+CDDL and shall be governed by the laws of the State of
+California (excluding conflict-of-law provisions). Any
+litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
+
+----------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..7c0a25a
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2 @@
+2007-30-10 Alberto Ruiz <alberto.ruiz@sun.com>
+ * Initial commit.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..54caf7c
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,229 @@
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..30ef62e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = src
+
+spidir=@APOCDIR@
+
+spi_DATA=build/class/spi.jar
+
+clean-local:
+ rm -rf build
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..f3276d3
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+PROJECT=APOC
+TEST_TYPE=-f
+FILE=src/com/sun/apoc/spi/build.xml.in
+
+DIE=0
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "You must have autoconf installed to compile $PROJECT."
+ echo "Install the appropriate package for your distribution,"
+ echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+ DIE=1
+}
+
+
+AM1_10=`which automake-1.10.1`
+AM1_9=`which automake-1.9`
+
+if test -x "`which automake-1.9`"
+then
+ AUTOMAKE=`which automake-1.9`
+ ACLOCAL=`which aclocal-1.9`
+ ACLOCAL_FLAGS="-I m4/"
+elif test -x "`which automake-1.10`"
+then
+ AUTOMAKE=`which automake-1.10`
+ ACLOCAL=`which aclocal-1.10`
+ ACLOCAL_FLAGS="-I m4/"
+else
+ echo
+ echo "You must have automake 1.10.x or 1.9.x installed to compile $PROJECT."
+ echo "Install the appropriate package for your distribution,"
+ echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+ DIE=1
+fi
+
+if test "$DIE" -eq 1; then
+ exit 1
+fi
+
+test $TEST_TYPE $FILE || {
+ echo "You must run this script in the top-level $PROJECT directory"
+ exit 1
+}
+
+if test -z "$AUTOGEN_SUBDIR_MODE"; then
+ if test -z "$*"; then
+ echo "I am going to run ./configure with no arguments - if you wish "
+ echo "to pass any to it, please specify them on the $0 command line."
+ fi
+fi
+
+rm -rf autom4te.cache
+
+$ACLOCAL $ACLOCAL_FLAGS || exit $?
+$AUTOMAKE --add-missing || exit $?
+autoconf || exit $?
+cd $ORIGDIR || exit $?
+
+if test -z "$AUTOGEN_SUBDIR_MODE"; then
+ $srcdir/configure --enable-maintainer-mode $AUTOGEN_CONFIGURE_ARGS "$@" || exit $?
+
+ echo
+ echo "Now type 'make' to compile $PROJECT."
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..e9c36d8
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,62 @@
+AC_INIT(apoc-spi, 1.0)
+
+AM_INIT_AUTOMAKE
+AC_JAVA_OPTIONS
+
+AC_EXPAND(datadir, NONE, EXPANDED_DATADIR)
+
+APOCDIR=$EXPANDED_DATADIR'/lib/apoc'
+
+AC_ARG_WITH(apoc-path,
+AC_HELP_STRING( [--with-apoc-path=DIR],
+ [specify a path to install the apoc libraries (DATADIR/lib/apoc)]),
+[
+ if test "$withval" != "no"
+ then
+ APOCDIR=$withval
+ fi
+])
+
+LDAPJDK=$APOCDIR/ldapjdk.jar
+
+AC_ARG_WITH(ns-ldap-path,
+AC_HELP_STRING( [--with-ns-ldap-path=DIR],
+ [specify the Netscape's LDAP JDK path or jar file (APOCDIR/ldapjdk.jar)]),
+[
+ if test "$withval" != "no"
+ then
+ LDAPJDK=$withval
+ fi
+])
+
+CLASSPATH="$APOCDIR:$LDAPJDK:.:$CLASSPATH"
+export CLASSPATH
+
+AC_PROG_JAVA
+AC_PROG_JAR
+AC_CHECK_CLASS(netscape.ldap.LDAPConnection, [], [
+echo
+AC_MSG_ERROR(Mozilla/Netscape LDAP JDK not found in Classpath.
+If it is already installed please use --with-ns-ldap-path=DIR to point to the path or jar file.)
+])
+
+
+AC_CHECK_PROG(ANT, ant, ant, no)
+if test $ANT == "no"
+then
+ AC_MSG_ERROR(Apache's Ant was not found in path.)
+fi
+
+AC_SUBST(APOCDIR)
+AC_SUBST(LDAPJDK)
+
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+src/com/Makefile
+src/com/sun/Makefile
+src/com/sun/apoc/Makefile
+src/com/sun/apoc/spi/Makefile
+src/com/sun/apoc/spi/build.xml
+])
diff --git a/m4/ac_check_class.m4 b/m4/ac_check_class.m4
new file mode 100644
index 0000000..b12e7f0
--- /dev/null
+++ b/m4/ac_check_class.m4
@@ -0,0 +1,107 @@
+dnl @synopsis AC_CHECK_CLASS
+dnl
+dnl AC_CHECK_CLASS tests the existence of a given Java class, either in
+dnl a jar or in a '.class' file.
+dnl
+dnl *Warning*: its success or failure can depend on a proper setting of the
+dnl CLASSPATH env. variable.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version $Id: ac_check_class.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_CHECK_CLASS],[
+AC_REQUIRE([AC_PROG_JAVA])
+ac_var_name=`echo $1 | sed 's/\./_/g'`
+dnl Normaly I'd use a AC_CACHE_CHECK here but since the variable name is
+dnl dynamic I need an extra level of extraction
+AC_MSG_CHECKING([for $1 class])
+AC_CACHE_VAL(ac_cv_class_$ac_var_name, [
+if test x$ac_cv_prog_uudecode_base64 = xyes; then
+dnl /**
+dnl * Test.java: used to test dynamicaly if a class exists.
+dnl */
+dnl public class Test
+dnl {
+dnl
+dnl public static void
+dnl main( String[] argv )
+dnl {
+dnl Class lib;
+dnl if (argv.length < 1)
+dnl {
+dnl System.err.println ("Missing argument");
+dnl System.exit (77);
+dnl }
+dnl try
+dnl {
+dnl lib = Class.forName (argv[0]);
+dnl }
+dnl catch (ClassNotFoundException e)
+dnl {
+dnl System.exit (1);
+dnl }
+dnl lib = null;
+dnl System.exit (0);
+dnl }
+dnl
+dnl }
+cat << \EOF > Test.uue
+begin-base64 644 Test.class
+yv66vgADAC0AKQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE
+bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51
+bWJlclRhYmxlDAAKAAsBAANlcnIBABVMamF2YS9pby9QcmludFN0cmVhbTsJ
+AA0ACQcADgEAEGphdmEvbGFuZy9TeXN0ZW0IABABABBNaXNzaW5nIGFyZ3Vt
+ZW50DAASABMBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgAV
+ABEHABYBABNqYXZhL2lvL1ByaW50U3RyZWFtDAAYABkBAARleGl0AQAEKEkp
+VgoADQAXDAAcAB0BAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylM
+amF2YS9sYW5nL0NsYXNzOwoAHwAbBwAgAQAPamF2YS9sYW5nL0NsYXNzBwAi
+AQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BAAY8aW5pdD4B
+AAMoKVYMACMAJAoAAwAlAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQAhAAEA
+AwAAAAAAAgAJAAUABgABAAcAAABtAAMAAwAAACkqvgSiABCyAAwSD7YAFBBN
+uAAaKgMyuAAeTKcACE0EuAAaAUwDuAAasQABABMAGgAdACEAAQAIAAAAKgAK
+AAAACgAAAAsABgANAA4ADgATABAAEwASAB4AFgAiABgAJAAZACgAGgABACMA
+JAABAAcAAAAhAAEAAQAAAAUqtwAmsQAAAAEACAAAAAoAAgAAAAQABAAEAAEA
+JwAAAAIAKA==
+====
+EOF
+ if uudecode$EXEEXT Test.uue; then
+ :
+ else
+ echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AC_FD_CC
+ echo "configure: failed file was:" >&AC_FD_CC
+ cat Test.uue >&AC_FD_CC
+ ac_cv_prog_uudecode_base64=no
+ fi
+ rm -f Test.uue
+ if AC_TRY_COMMAND($JAVA $JAVAFLAGS Test $1) >/dev/null 2>&1; then
+ eval "ac_cv_class_$ac_var_name=yes"
+ else
+ eval "ac_cv_class_$ac_var_name=no"
+ fi
+ rm -f Test.class
+else
+ AC_TRY_COMPILE_JAVA([$1], , [eval "ac_cv_class_$ac_var_name=yes"],
+ [eval "ac_cv_class_$ac_var_name=no"])
+fi
+eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`"
+eval "HAVE_$ac_var_name=$`echo ac_cv_class_$ac_var_val`"
+HAVE_LAST_CLASS=$ac_var_val
+if test x$ac_var_val = xyes; then
+ ifelse([$2], , :, [$2])
+else
+ ifelse([$3], , :, [$3])
+fi
+])
+dnl for some reason the above statment didn't fall though here?
+dnl do scripts have variable scoping?
+eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`"
+AC_MSG_RESULT($ac_var_val)
+])
diff --git a/m4/ac_check_classpath.m4 b/m4/ac_check_classpath.m4
new file mode 100644
index 0000000..b18d479
--- /dev/null
+++ b/m4/ac_check_classpath.m4
@@ -0,0 +1,23 @@
+dnl @synopsis AC_CHECK_CLASSPATH
+dnl
+dnl AC_CHECK_CLASSPATH just displays the CLASSPATH, for the edification
+dnl of the user.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version $Id: ac_check_classpath.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_CHECK_CLASSPATH],[
+if test "x$CLASSPATH" = x; then
+ echo "You have no CLASSPATH, I hope it is good"
+else
+ echo "You have CLASSPATH $CLASSPATH, hope it is correct"
+fi
+])
diff --git a/m4/ac_check_junit.m4 b/m4/ac_check_junit.m4
new file mode 100644
index 0000000..cc02e32
--- /dev/null
+++ b/m4/ac_check_junit.m4
@@ -0,0 +1,54 @@
+dnl @synopsis AC_CHECK_JUNIT
+dnl
+dnl AC_CHECK_JUNIT tests the availability of the Junit testing
+dnl framework, and set some variables for conditional compilation
+dnl of the test suite by automake.
+dnl
+dnl If available, JUNIT is set to a command launching the text
+dnl based user interface of Junit, @JAVA_JUNIT@ is set to $JAVA_JUNIT
+dnl and @TESTS_JUNIT@ is set to $TESTS_JUNIT, otherwise they are set
+dnl to empty values.
+dnl
+dnl You can use these variables in your Makefile.am file like this :
+dnl
+dnl # Some of the following classes are built only if junit is available
+dnl JAVA_JUNIT = Class1Test.java Class2Test.java AllJunitTests.java
+dnl
+dnl noinst_JAVA = Example1.java Example2.java @JAVA_JUNIT@
+dnl
+dnl EXTRA_JAVA = $(JAVA_JUNIT)
+dnl
+dnl TESTS_JUNIT = AllJunitTests
+dnl
+dnl TESTS = StandaloneTest1 StandaloneTest2 @TESTS_JUNIT@
+dnl
+dnl EXTRA_TESTS = $(TESTS_JUNIT)
+dnl
+dnl AllJunitTests :
+dnl echo "#! /bin/sh" > $@
+dnl echo "exec @JUNIT@ my.package.name.AllJunitTests" >> $@
+dnl chmod +x $@
+dnl
+dnl @author Luc Maisonobe
+dnl @version $Id: ac_check_junit.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_CHECK_JUNIT],[
+AC_CACHE_VAL(ac_cv_prog_JUNIT,[
+AC_CHECK_CLASS(junit.textui.TestRunner)
+if test x"`eval 'echo $ac_cv_class_junit_textui_TestRunner'`" != xno ; then
+ ac_cv_prog_JUNIT='$(CLASSPATH_ENV) $(JAVA) $(JAVAFLAGS) junit.textui.TestRunner'
+fi])
+AC_MSG_CHECKING([for junit])
+if test x"`eval 'echo $ac_cv_prog_JUNIT'`" != x ; then
+ JUNIT="$ac_cv_prog_JUNIT"
+ JAVA_JUNIT='$(JAVA_JUNIT)'
+ TESTS_JUNIT='$(TESTS_JUNIT)'
+else
+ JUNIT=
+ JAVA_JUNIT=
+ TESTS_JUNIT=
+fi
+AC_MSG_RESULT($JAVA_JUNIT)
+AC_SUBST(JUNIT)
+AC_SUBST(JAVA_JUNIT)
+AC_SUBST(TESTS_JUNIT)])
diff --git a/m4/ac_check_rqrd_class.m4 b/m4/ac_check_rqrd_class.m4
new file mode 100644
index 0000000..c7c26b8
--- /dev/null
+++ b/m4/ac_check_rqrd_class.m4
@@ -0,0 +1,26 @@
+dnl @synopsis AC_CHECK_RQRD_CLASS
+dnl
+dnl AC_CHECK_RQRD_CLASS tests the existence of a given Java class, either in
+dnl a jar or in a '.class' file and fails if it doesn't exist.
+dnl Its success or failure can depend on a proper setting of the
+dnl CLASSPATH env. variable.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version $Id: ac_check_rqrd_class.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+
+AC_DEFUN([AC_CHECK_RQRD_CLASS],[
+CLASS=`echo $1|sed 's/\./_/g'`
+AC_CHECK_CLASS($1)
+if test "$HAVE_LAST_CLASS" = "no"; then
+ AC_MSG_ERROR([Required class $1 missing, exiting.])
+fi
+])
diff --git a/m4/ac_expand.m4 b/m4/ac_expand.m4
new file mode 100644
index 0000000..ae8188a
--- /dev/null
+++ b/m4/ac_expand.m4
@@ -0,0 +1,8 @@
+AC_DEFUN([AC_EXPAND], [
+ test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+ ac_expand=[$]$1
+ test "x$ac_expand" = xNONE && ac_expand="[$]$2"
+ ac_expand=`eval echo [$]ac_expand`
+ $3=`eval echo [$]ac_expand`
+])
diff --git a/m4/ac_java_options.m4 b/m4/ac_java_options.m4
new file mode 100644
index 0000000..e71adfe
--- /dev/null
+++ b/m4/ac_java_options.m4
@@ -0,0 +1,32 @@
+dnl @synopsis AC_JAVA_OPTIONS
+dnl
+dnl AC_JAVA_OPTIONS adds configure command line options used for Java m4
+dnl macros. This Macro is optional.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Devin Weaver <ktohg@tritarget.com>
+dnl @version $Id: ac_java_options.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_JAVA_OPTIONS],[
+AC_ARG_WITH(java-prefix,
+ [ --with-java-prefix=PFX prefix where Java runtime is installed (optional)])
+AC_ARG_WITH(javac-flags,
+ [ --with-javac-flags=FLAGS flags to pass to the Java compiler (optional)])
+AC_ARG_WITH(java-flags,
+ [ --with-java-flags=FLAGS flags to pass to the Java VM (optional)])
+JAVAPREFIX=$with_java_prefix
+JAVACFLAGS=$with_javac_flags
+JAVAFLAGS=$with_java_flags
+AC_SUBST(JAVAPREFIX)dnl
+AC_SUBST(JAVACFLAGS)dnl
+AC_SUBST(JAVAFLAGS)dnl
+AC_SUBST(JAVA)dnl
+AC_SUBST(JAVAC)dnl
+])
diff --git a/m4/ac_prog_jar.m4 b/m4/ac_prog_jar.m4
new file mode 100644
index 0000000..c60a79a
--- /dev/null
+++ b/m4/ac_prog_jar.m4
@@ -0,0 +1,36 @@
+dnl @synopsis AC_PROG_JAR
+dnl
+dnl AC_PROG_JAR tests for an existing jar program. It uses the environment
+dnl variable JAR then tests in sequence various common jar programs.
+dnl
+dnl If you want to force a specific compiler:
+dnl
+dnl - at the configure.in level, set JAR=yourcompiler before calling
+dnl AC_PROG_JAR
+dnl
+dnl - at the configure level, setenv JAR
+dnl
+dnl You can use the JAR variable in your Makefile.in, with @JAR@.
+dnl
+dnl Note: This macro depends on the autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download that whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl
+dnl The general documentation of those macros, as well as the sample
+dnl configure.in, is included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Egon Willighagen <egonw@sci.kun.nl>
+dnl @version $Id: ac_prog_jar.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_PROG_JAR],[
+AC_REQUIRE([AC_EXEEXT])dnl
+if test "x$JAVAPREFIX" = x; then
+ test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar$EXEEXT)
+else
+ test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar, $JAVAPREFIX)
+fi
+test "x$JAR" = x && AC_MSG_ERROR([no acceptable jar program found in \$PATH])
+AC_PROVIDE([$0])dnl
+])
diff --git a/m4/ac_prog_java.m4 b/m4/ac_prog_java.m4
new file mode 100644
index 0000000..05c65e7
--- /dev/null
+++ b/m4/ac_prog_java.m4
@@ -0,0 +1,79 @@
+dnl @synopsis AC_PROG_JAVA
+dnl
+dnl Here is a summary of the main macros:
+dnl
+dnl AC_PROG_JAVAC: finds a Java compiler.
+dnl
+dnl AC_PROG_JAVA: finds a Java virtual machine.
+dnl
+dnl AC_CHECK_CLASS: finds if we have the given class (beware of CLASSPATH!).
+dnl
+dnl AC_CHECK_RQRD_CLASS: finds if we have the given class and stops otherwise.
+dnl
+dnl AC_TRY_COMPILE_JAVA: attempt to compile user given source.
+dnl
+dnl AC_TRY_RUN_JAVA: attempt to compile and run user given source.
+dnl
+dnl AC_JAVA_OPTIONS: adds Java configure options.
+dnl
+dnl AC_PROG_JAVA tests an existing Java virtual machine. It uses the
+dnl environment variable JAVA then tests in sequence various common Java
+dnl virtual machines. For political reasons, it starts with the free ones.
+dnl You *must* call [AC_PROG_JAVAC] before.
+dnl
+dnl If you want to force a specific VM:
+dnl
+dnl - at the configure.in level, set JAVA=yourvm before calling AC_PROG_JAVA
+dnl (but after AC_INIT)
+dnl
+dnl - at the configure level, setenv JAVA
+dnl
+dnl You can use the JAVA variable in your Makefile.in, with @JAVA@.
+dnl
+dnl *Warning*: its success or failure can depend on a proper setting of the
+dnl CLASSPATH env. variable.
+dnl
+dnl TODO: allow to exclude virtual machines (rationale: most Java programs
+dnl cannot run with some VM like kaffe).
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl
+dnl A Web page, with a link to the latest CVS snapshot is at
+dnl <http://www.internatif.org/bortzmeyer/autoconf-Java/>.
+dnl
+dnl This is a sample configure.in
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl AC_INIT(UnTag.java)
+dnl
+dnl dnl Checks for programs.
+dnl AC_CHECK_CLASSPATH
+dnl AC_PROG_JAVAC
+dnl AC_PROG_JAVA
+dnl
+dnl dnl Checks for classes
+dnl AC_CHECK_RQRD_CLASS(org.xml.sax.Parser)
+dnl AC_CHECK_RQRD_CLASS(com.jclark.xml.sax.Driver)
+dnl
+dnl AC_OUTPUT(Makefile)
+dnl
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version $Id: ac_prog_java.ac,v 12.1 2006/08/24 14:45:36 bostic Exp $
+dnl
+dnl Note: Modified to prefer java over kaffe. [#8059]
+dnl
+AC_DEFUN([AC_PROG_JAVA],[
+AC_REQUIRE([AC_EXEEXT])dnl
+if test x$JAVAPREFIX = x; then
+ test x$JAVA = x && AC_CHECK_PROGS(JAVA, java$EXEEXT kaffe$EXEEXT)
+else
+ test x$JAVA = x && AC_CHECK_PROGS(JAVA, java$EXEEXT kaffe$EXEEXT, $JAVAPREFIX)
+fi
+test x$JAVA = x && AC_MSG_ERROR([no acceptable Java virtual machine found in \$PATH])
+AC_PROG_JAVA_WORKS
+AC_PROVIDE([$0])dnl
+])
diff --git a/m4/ac_prog_java_works.m4 b/m4/ac_prog_java_works.m4
new file mode 100644
index 0000000..f0ff8c5
--- /dev/null
+++ b/m4/ac_prog_java_works.m4
@@ -0,0 +1,97 @@
+dnl @synopsis AC_PROG_JAVA_WORKS
+dnl
+dnl Internal use ONLY.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version $Id: ac_prog_java_works.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_PROG_JAVA_WORKS], [
+AC_CHECK_PROG(uudecode, uudecode$EXEEXT, yes)
+if test x$uudecode = xyes; then
+AC_CACHE_CHECK([if uudecode can decode base 64 file], ac_cv_prog_uudecode_base64, [
+dnl /**
+dnl * Test.java: used to test if java compiler works.
+dnl */
+dnl public class Test
+dnl {
+dnl
+dnl public static void
+dnl main( String[] argv )
+dnl {
+dnl System.exit (0);
+dnl }
+dnl
+dnl }
+cat << \EOF > Test.uue
+begin-base64 644 Test.class
+yv66vgADAC0AFQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE
+bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51
+bWJlclRhYmxlDAAKAAsBAARleGl0AQAEKEkpVgoADQAJBwAOAQAQamF2YS9s
+YW5nL1N5c3RlbQEABjxpbml0PgEAAygpVgwADwAQCgADABEBAApTb3VyY2VG
+aWxlAQAJVGVzdC5qYXZhACEAAQADAAAAAAACAAkABQAGAAEABwAAACEAAQAB
+AAAABQO4AAyxAAAAAQAIAAAACgACAAAACgAEAAsAAQAPABAAAQAHAAAAIQAB
+AAEAAAAFKrcAErEAAAABAAgAAAAKAAIAAAAEAAQABAABABMAAAACABQ=
+====
+EOF
+if uudecode$EXEEXT Test.uue; then
+ ac_cv_prog_uudecode_base64=yes
+else
+ echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AC_FD_CC
+ echo "configure: failed file was:" >&AC_FD_CC
+ cat Test.uue >&AC_FD_CC
+ ac_cv_prog_uudecode_base64=no
+fi
+rm -f Test.uue])
+fi
+if test x$ac_cv_prog_uudecode_base64 != xyes; then
+ rm -f Test.class
+ AC_MSG_WARN([I have to compile Test.class from scratch])
+ if test x$ac_cv_prog_javac_works = xno; then
+ AC_MSG_ERROR([Cannot compile java source. $JAVAC does not work properly])
+ fi
+ if test x$ac_cv_prog_javac_works = x; then
+ AC_PROG_JAVAC
+ fi
+fi
+AC_CACHE_CHECK(if $JAVA works, ac_cv_prog_java_works, [
+JAVA_TEST=Test.java
+CLASS_TEST=Test.class
+TEST=Test
+changequote(, )dnl
+cat << \EOF > $JAVA_TEST
+/* [#]line __oline__ "configure" */
+public class Test {
+public static void main (String args[]) {
+ System.exit (0);
+} }
+EOF
+changequote([, ])dnl
+if test x$ac_cv_prog_uudecode_base64 != xyes; then
+ if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) && test -s $CLASS_TEST; then
+ :
+ else
+ echo "configure: failed program was:" >&AC_FD_CC
+ cat $JAVA_TEST >&AC_FD_CC
+ AC_MSG_ERROR(The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?))
+ fi
+fi
+if AC_TRY_COMMAND($JAVA $JAVAFLAGS $TEST) >/dev/null 2>&1; then
+ ac_cv_prog_java_works=yes
+else
+ echo "configure: failed program was:" >&AC_FD_CC
+ cat $JAVA_TEST >&AC_FD_CC
+ AC_MSG_ERROR(The Java VM $JAVA failed (see config.log, check the CLASSPATH?))
+fi
+rm -fr $JAVA_TEST $CLASS_TEST Test.uue
+])
+AC_PROVIDE([$0])dnl
+]
+)
diff --git a/m4/ac_prog_javac.m4 b/m4/ac_prog_javac.m4
new file mode 100644
index 0000000..b3607dc
--- /dev/null
+++ b/m4/ac_prog_javac.m4
@@ -0,0 +1,43 @@
+dnl @synopsis AC_PROG_JAVAC
+dnl
+dnl AC_PROG_JAVAC tests an existing Java compiler. It uses the environment
+dnl variable JAVAC then tests in sequence various common Java compilers. For
+dnl political reasons, it starts with the free ones.
+dnl
+dnl If you want to force a specific compiler:
+dnl
+dnl - at the configure.in level, set JAVAC=yourcompiler before calling
+dnl AC_PROG_JAVAC
+dnl
+dnl - at the configure level, setenv JAVAC
+dnl
+dnl You can use the JAVAC variable in your Makefile.in, with @JAVAC@.
+dnl
+dnl *Warning*: its success or failure can depend on a proper setting of the
+dnl CLASSPATH env. variable.
+dnl
+dnl TODO: allow to exclude compilers (rationale: most Java programs cannot compile
+dnl with some compilers like guavac).
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version $Id: ac_prog_javac.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_PROG_JAVAC],[
+AC_REQUIRE([AC_EXEEXT])dnl
+if test "x$JAVAPREFIX" = x; then
+ test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT)
+else
+ test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, javac$EXEEXT "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT, $JAVAPREFIX)
+fi
+test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH])
+AC_PROG_JAVAC_WORKS
+AC_PROVIDE([$0])dnl
+])
diff --git a/m4/ac_prog_javac_works.m4 b/m4/ac_prog_javac_works.m4
new file mode 100644
index 0000000..0cfd1f2
--- /dev/null
+++ b/m4/ac_prog_javac_works.m4
@@ -0,0 +1,35 @@
+dnl @synopsis AC_PROG_JAVAC_WORKS
+dnl
+dnl Internal use ONLY.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
+dnl @version $Id: ac_prog_javac_works.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_PROG_JAVAC_WORKS],[
+AC_CACHE_CHECK([if $JAVAC works], ac_cv_prog_javac_works, [
+JAVA_TEST=Test.java
+CLASS_TEST=Test.class
+cat << \EOF > $JAVA_TEST
+/* [#]line __oline__ "configure" */
+public class Test {
+}
+EOF
+if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) >/dev/null 2>&1; then
+ ac_cv_prog_javac_works=yes
+else
+ AC_MSG_ERROR([The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)])
+ echo "configure: failed program was:" >&AC_FD_CC
+ cat $JAVA_TEST >&AC_FD_CC
+fi
+rm -f $JAVA_TEST $CLASS_TEST
+])
+AC_PROVIDE([$0])dnl
+])
diff --git a/m4/ac_prog_javadoc.m4 b/m4/ac_prog_javadoc.m4
new file mode 100644
index 0000000..36b95bd
--- /dev/null
+++ b/m4/ac_prog_javadoc.m4
@@ -0,0 +1,37 @@
+dnl @synopsis AC_PROG_JAVADOC
+dnl
+dnl AC_PROG_JAVADOC tests for an existing javadoc generator. It uses the environment
+dnl variable JAVADOC then tests in sequence various common javadoc generator.
+dnl
+dnl If you want to force a specific compiler:
+dnl
+dnl - at the configure.in level, set JAVADOC=yourgenerator before calling
+dnl AC_PROG_JAVADOC
+dnl
+dnl - at the configure level, setenv JAVADOC
+dnl
+dnl You can use the JAVADOC variable in your Makefile.in, with @JAVADOC@.
+dnl
+dnl Note: This macro depends on the autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download that whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl
+dnl The general documentation of those macros, as well as the sample
+dnl configure.in, is included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Egon Willighagen <egonw@sci.kun.nl>
+dnl @version $Id: ac_prog_javadoc.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_PROG_JAVADOC],[
+AC_REQUIRE([AC_EXEEXT])dnl
+if test "x$JAVAPREFIX" = x; then
+ test "x$JAVADOC" = x && AC_CHECK_PROGS(JAVADOC, javadoc$EXEEXT)
+else
+ test "x$JAVADOC" = x && AC_CHECK_PROGS(JAVADOC, javadoc, $JAVAPREFIX)
+fi
+test "x$JAVADOC" = x && AC_MSG_ERROR([no acceptable javadoc generator found in \$PATH])
+AC_PROVIDE([$0])dnl
+])
+
diff --git a/m4/ac_prog_javah.m4 b/m4/ac_prog_javah.m4
new file mode 100644
index 0000000..7563036
--- /dev/null
+++ b/m4/ac_prog_javah.m4
@@ -0,0 +1,26 @@
+dnl @synopsis AC_PROG_JAVAH
+dnl
+dnl AC_PROG_JAVAH tests the availability of the javah header generator
+dnl and looks for the jni.h header file. If available, JAVAH is set to
+dnl the full path of javah and CPPFLAGS is updated accordingly.
+dnl
+dnl @author Luc Maisonobe
+dnl @version $Id: ac_prog_javah.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_PROG_JAVAH],[
+AC_REQUIRE([AC_CANONICAL_SYSTEM])dnl
+AC_REQUIRE([AC_PROG_CPP])dnl
+AC_PATH_PROG(JAVAH,javah)
+if test x"`eval 'echo $ac_cv_path_JAVAH'`" != x ; then
+ AC_TRY_CPP([#include <jni.h>],,[
+ ac_save_CPPFLAGS="$CPPFLAGS"
+changequote(, )dnl
+ ac_dir=`echo $ac_cv_path_JAVAH | sed 's,\(.*\)/[^/]*/[^/]*$,\1/include,'`
+ ac_machdep=`echo $build_os | sed 's,[-0-9].*,,'`
+changequote([, ])dnl
+ CPPFLAGS="$ac_save_CPPFLAGS -I$ac_dir -I$ac_dir/$ac_machdep"
+ AC_TRY_CPP([#include <jni.h>],
+ ac_save_CPPFLAGS="$CPPFLAGS",
+ AC_MSG_WARN([unable to include <jni.h>]))
+ CPPFLAGS="$ac_save_CPPFLAGS"])
+fi])
diff --git a/m4/ac_try_compile_java.m4 b/m4/ac_try_compile_java.m4
new file mode 100644
index 0000000..d22aeab
--- /dev/null
+++ b/m4/ac_try_compile_java.m4
@@ -0,0 +1,39 @@
+dnl @synopsis AC_TRY_COMPILE_JAVA
+dnl
+dnl AC_TRY_COMPILE_JAVA attempt to compile user given source.
+dnl
+dnl *Warning*: its success or failure can depend on a proper setting of the
+dnl CLASSPATH env. variable.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Devin Weaver <ktohg@tritarget.com>
+dnl @version $Id: ac_try_compile_java.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_TRY_COMPILE_JAVA],[
+AC_REQUIRE([AC_PROG_JAVAC])dnl
+cat << \EOF > Test.java
+/* [#]line __oline__ "configure" */
+ifelse([$1], , , [import $1;])
+public class Test {
+[$2]
+}
+EOF
+if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class
+then
+dnl Don't remove the temporary files here, so they can be examined.
+ ifelse([$3], , :, [$3])
+else
+ echo "configure: failed program was:" >&AC_FD_CC
+ cat Test.java >&AC_FD_CC
+ifelse([$4], , , [ rm -fr Test*
+ $4
+])dnl
+fi
+rm -fr Test*])
diff --git a/m4/ac_try_run_javac.m4 b/m4/ac_try_run_javac.m4
new file mode 100644
index 0000000..0124935
--- /dev/null
+++ b/m4/ac_try_run_javac.m4
@@ -0,0 +1,40 @@
+dnl @synopsis AC_TRY_RUN_JAVA
+dnl
+dnl AC_TRY_RUN_JAVA attempt to compile and run user given source.
+dnl
+dnl *Warning*: its success or failure can depend on a proper setting of the
+dnl CLASSPATH env. variable.
+dnl
+dnl Note: This is part of the set of autoconf M4 macros for Java programs.
+dnl It is VERY IMPORTANT that you download the whole set, some
+dnl macros depend on other. Unfortunately, the autoconf archive does not
+dnl support the concept of set of macros, so I had to break it for
+dnl submission.
+dnl The general documentation, as well as the sample configure.in, is
+dnl included in the AC_PROG_JAVA macro.
+dnl
+dnl @author Devin Weaver <ktohg@tritarget.com>
+dnl @version $Id: ac_try_run_javac.ac,v 12.0 2004/11/17 03:43:38 bostic Exp $
+dnl
+AC_DEFUN([AC_TRY_RUN_JAVA],[
+AC_REQUIRE([AC_PROG_JAVAC])dnl
+AC_REQUIRE([AC_PROG_JAVA])dnl
+cat << \EOF > Test.java
+/* [#]line __oline__ "configure" */
+ifelse([$1], , , [include $1;])
+public class Test {
+[$2]
+}
+EOF
+if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class && ($JAVA $JAVAFLAGS Test; exit) 2>/dev/null
+then
+dnl Don't remove the temporary files here, so they can be examined.
+ ifelse([$3], , :, [$3])
+else
+ echo "configure: failed program was:" >&AC_FD_CC
+ cat Test.java >&AC_FD_CC
+ifelse([$4], , , [ rm -fr Test*
+ $4
+])dnl
+fi
+rm -fr Test*])
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..17e533f
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = com
diff --git a/src/com/Makefile.am b/src/com/Makefile.am
new file mode 100644
index 0000000..1d06788
--- /dev/null
+++ b/src/com/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = sun
diff --git a/src/com/sun/Makefile.am b/src/com/sun/Makefile.am
new file mode 100644
index 0000000..b5d5f2c
--- /dev/null
+++ b/src/com/sun/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = apoc
diff --git a/src/com/sun/apoc/Makefile.am b/src/com/sun/apoc/Makefile.am
new file mode 100644
index 0000000..4a79963
--- /dev/null
+++ b/src/com/sun/apoc/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = spi
diff --git a/src/com/sun/apoc/spi/AbstractAssignmentProvider.java b/src/com/sun/apoc/spi/AbstractAssignmentProvider.java
new file mode 100644
index 0000000..cf9875f
--- /dev/null
+++ b/src/com/sun/apoc/spi/AbstractAssignmentProvider.java
@@ -0,0 +1,225 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.TreeSet;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.NullProfileException;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileComparatorProvider;
+
+public abstract class AbstractAssignmentProvider
+ implements AssignmentProvider {
+
+ protected PolicySource mPolicySource;
+
+ /**
+ * Assigns a profile to an entity.
+ * Verify if the Applicability of the Profile is
+ * compatible with the type of Entity:
+ * <li>A profile with Applicabity.USER can be assigned
+ * to a Organization, User or Role defined in an Organization.</li>
+ * <li>A profile with Applicabity.HOST can be assigned
+ * to a Domain, Host or Role defined in Domain.</li>
+ * <li>A profile with Applicabity.ALL can be assigned
+ * to any entity</li>
+ *
+ * @param entity entity to assign the profile to
+ * @param profile profile to assign to the entity
+ * @throws <code>SPIException</code> if error occurs
+ * @throws <code>IllegalAssignmentException</code>
+ * if Applicability of the profile is not
+ * compatible with the type of entity
+ */
+ public void assignProfile(Entity entity, Profile profile)
+ throws SPIException {
+ // check that profile is not already assigned
+ Iterator profiles = getAssignedProfiles(entity);
+ while (profiles.hasNext()) {
+ Profile assignedProfile = (Profile)profiles.next();
+ if (profile.equals(assignedProfile)) {
+ return;
+ }
+ }
+ if (!isCompatible(entity, profile)){
+ throw new IllegalAssignmentException (
+ profile.getApplicability().getStringValue(), "") ;
+ }
+ assignProfileToEntity(entity, profile);
+ }
+
+ /**
+ * Assigns a profile to an entity.
+ *
+ * @param entity entity to assign the profile to
+ * @param profile profile to assign to the entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ protected abstract void assignProfileToEntity(Entity entity, Profile profile)
+ throws SPIException;
+
+ /**
+ * Unassigns the specified profile from the entity.
+ *
+ * @param entity entity to unassign the profile to
+ * @param profile profile to unassign to the entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void unassignProfile(Entity entity, Profile profile)
+ throws SPIException;
+
+ /**
+ * returns the profiles assigned to the entity.
+ * Returns only the profiles that have an Applicability
+ * compatible with the entity type.
+ * The profiles are ordered occording to their priority.
+ *
+ * @param entity entity to get assigned profiles from
+ * @return Iterator on the assigned Profiles
+ * @throws <code>SPIException</code> if error occurs
+ * @see AssignmentProvider#assignProfile(Entity, Profile)
+ */
+ public Iterator getAssignedProfiles(Entity entity)
+ throws SPIException {
+ Comparator comparator =
+ ((ProfileComparatorProvider)mPolicySource.getProfileProvider())
+ .getProfileComparator();
+ TreeSet assignedProfiles = new TreeSet(comparator);
+ Iterator iterProfiles = getProfilesAssignedToEntity(entity);
+ while (iterProfiles.hasNext()) {
+ Profile profile = (Profile)iterProfiles.next();
+ if (isCompatible(entity, profile)) {
+ assignedProfiles.add(profile);
+ }
+ }
+ return assignedProfiles.iterator();
+ }
+
+ /**
+ * returns the profiles assigned to the entity.
+ *
+ * @param entity entity to get assigned profiles from
+ * @return Iterator on the assigned Profiles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ protected abstract Iterator getProfilesAssignedToEntity(Entity entity)
+ throws SPIException;
+
+ /**
+ * returns the entities the profile is assigned to.
+ * Returns only the entities that have a type
+ * compatible with the profile Applicability.
+ *
+ * @param profile profile to get assigned Entities from
+ * @return Iterator on the assigned Entities
+ * @throws <code>SPIException</code> if error occurs
+ * @see AssignmentProvider#assignProfile(Entity, Profile)
+ */
+ public Iterator getAssignedEntities(Profile profile) throws SPIException {
+ if (profile == null) {
+ throw new NullProfileException();
+ }
+ HashSet assignedEntities = new HashSet();
+ Iterator iterEntities = getEntitiesAssignedToProfile(profile);
+ while (iterEntities.hasNext()) {
+ Entity entity = (Entity)iterEntities.next();
+ if (isCompatible(entity, profile)) {
+ assignedEntities.add(entity);
+ }
+ }
+ return assignedEntities.iterator();
+ }
+
+ /**
+ * returns the entities the profile is assigned to.
+ *
+ * @param profile profile to get assigned Entities from
+ * @return Iterator on the assigned Entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ protected abstract Iterator getEntitiesAssignedToProfile(Profile profile)
+ throws SPIException;
+
+ /**
+ * Opens the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void open() throws SPIException;
+
+ /**
+ * Closes the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void close() throws SPIException;
+
+ /**
+ * Verify if the profile Applicability is compatible with
+ * the type of entity:
+ * <li>A profile with Applicabity.USER is compatible with
+ * a Organization, User or Role defined in an Organization.</li>
+ * <li>A profile with Applicabity.HOST is compatible with
+ * a Domain, Host or Role defined in Domain.</li>
+ * <li>A profile with Applicabity.ALL is compatible with
+ * any entity</li>
+ *
+ * @param entity Entity to verify
+ * @param profile Profile to verify
+ * @return true if profile Applicability is compatible
+ * with entity, false otherwise.
+ */
+ private boolean isCompatible(Entity entity, Profile profile) {
+ boolean compatible = false;
+ if ((profile != null) && (entity != null)){
+ Applicability profileApp = profile.getApplicability();
+ if (profileApp.equals(Applicability.ALL)){
+ compatible = true;
+ }
+ else if (profileApp.equals(Applicability.HOST)){
+ compatible = entity.getPolicySourceName().equals(EnvironmentConstants.HOST_SOURCE);
+ }
+ else if (profileApp.equals(Applicability.USER)){
+ compatible = entity.getPolicySourceName().equals(EnvironmentConstants.USER_SOURCE);
+ }
+ }
+ return compatible;
+ }
+}
diff --git a/src/com/sun/apoc/spi/AssignmentProvider.java b/src/com/sun/apoc/spi/AssignmentProvider.java
new file mode 100644
index 0000000..fbabdc9
--- /dev/null
+++ b/src/com/sun/apoc/spi/AssignmentProvider.java
@@ -0,0 +1,107 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.profiles.Profile;
+
+/**
+ * provides access to the assignments between Entities
+ * and Profiles, this is the link between Entities and
+ * Profiles
+ *
+ */
+public interface AssignmentProvider extends Provider {
+
+ /**
+ * Assigns a profile to an entity.
+ * Verify if the Applicability of the Profile is
+ * compatible with the type of Entity:
+ * <li>A profile with Applicabity.USER can be assigned
+ * to a Organization, User or Role defined in an Organization.</li>
+ * <li>A profile with Applicabity.HOST can be assigned
+ * to a Domain, Host or Role defined in Domain.</li>
+ * <li>A profile with Applicabity.ALL can be assigned
+ * to any entity</li>
+ *
+ * @param entity entity to assign the profile to
+ * @param profile profile to assign to the entity
+ * @throws <code>SPIException</code> if error occurs
+ * @throws <code>IllegalAssignmentException</code>
+ * if Applicability of the profile is not
+ * compatible with the type of entity
+ */
+ public void assignProfile(Entity entity, Profile profile)
+ throws SPIException;
+
+ /**
+ * Unassigns the specified profile from the entity.
+ *
+ * @param entity entity to unassign the profile to
+ * @param profile profile to unassign to the entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void unassignProfile(Entity entity, Profile profile)
+ throws SPIException;
+
+ /**
+ * returns the profiles assigned to the entity.
+ * Returns only the profiles that have an Applicability
+ * compatible with the entity type.
+ * The profiles are ordered occording to their priority.
+ *
+ * @param entity entity to get assigned profiles from
+ * @return Iterator on the assigned Profiles
+ * @throws <code>SPIException</code> if error occurs
+ * @see AssignmentProvider#assignProfile(Entity, Profile)
+ */
+ public Iterator getAssignedProfiles(Entity entity)
+ throws SPIException;
+
+ /**
+ * returns the entities the profile is assigned to.
+ * Returns only the entities that have a type
+ * compatible with the profile Applicability.
+ *
+ * @param profile profile to get assigned Entities from
+ * @return Iterator on the assigned Entities
+ * @throws <code>SPIException</code> if error occurs
+ * @see AssignmentProvider#assignProfile(Entity, Profile)
+ */
+ public Iterator getAssignedEntities(Profile profile)
+ throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/AuthenticationException.java b/src/com/sun/apoc/spi/AuthenticationException.java
new file mode 100644
index 0000000..2b9dbae
--- /dev/null
+++ b/src/com/sun/apoc/spi/AuthenticationException.java
@@ -0,0 +1,71 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class AuthenticationException extends ConnectionException {
+
+ private static final String AUTHENTICATION_KEY =
+ "error.spi.connection.authentication";
+ private static final String NOT_ALLOWED_AUTHENTICATION_KEY =
+ "error.spi.connection.authentication.notallowed";
+
+ protected String mUserName = null;
+
+ public AuthenticationException () {
+ super();
+ }
+
+ public AuthenticationException (String url, String userName) {
+ super(url);
+ mUserName = userName;
+ mMessageKey = NOT_ALLOWED_AUTHENTICATION_KEY;
+ mMessageParams = new Object[]{mUrl, mUserName};
+ }
+
+ public AuthenticationException (String url, Throwable cause) {
+ super(url, cause);
+ mMessageKey = AUTHENTICATION_KEY;
+ }
+
+ public AuthenticationException (String url, String userName,
+ Throwable cause) {
+ super(url, cause);
+ mUserName = userName;
+ mMessageKey = AUTHENTICATION_KEY;
+ mMessageParams = new Object[]{mUrl, mUserName};
+ }
+
+ public String getUserName() { return mUserName; }
+}
diff --git a/src/com/sun/apoc/spi/CloseConnectionException.java b/src/com/sun/apoc/spi/CloseConnectionException.java
new file mode 100644
index 0000000..ae25899
--- /dev/null
+++ b/src/com/sun/apoc/spi/CloseConnectionException.java
@@ -0,0 +1,50 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class CloseConnectionException extends ConnectionException {
+
+ private static final String CLOSE_CONNECTION_KEY =
+ "error.spi.connection.close";
+
+ public CloseConnectionException () {
+ super();
+ }
+
+ public CloseConnectionException (String url, Throwable cause) {
+ super(url, cause);
+ mMessageKey = CLOSE_CONNECTION_KEY;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ConnectionException.java b/src/com/sun/apoc/spi/ConnectionException.java
new file mode 100644
index 0000000..20a6da3
--- /dev/null
+++ b/src/com/sun/apoc/spi/ConnectionException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class ConnectionException extends SPIException {
+
+ private static final String CONNECTION_KEY =
+ "error.spi.connection";
+
+ protected String mUrl = null;
+
+ public ConnectionException () {
+ super();
+ }
+
+ public ConnectionException (String url) {
+ super();
+ mUrl = url;
+ mMessageKey = CONNECTION_KEY;
+ mMessageParams = new Object[]{mUrl};
+ }
+
+ public ConnectionException (String url, Throwable cause) {
+ super(cause);
+ mUrl = url;
+ mMessageKey = CONNECTION_KEY;
+ mMessageParams = new Object[]{mUrl};
+ }
+
+ public String getURL() {return mUrl;}
+}
diff --git a/src/com/sun/apoc/spi/ConnectionSizeLimitException.java b/src/com/sun/apoc/spi/ConnectionSizeLimitException.java
new file mode 100644
index 0000000..e009f63
--- /dev/null
+++ b/src/com/sun/apoc/spi/ConnectionSizeLimitException.java
@@ -0,0 +1,51 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class ConnectionSizeLimitException extends ConnectionException {
+
+ private static final String CONNECTION_SIZE_KEY =
+ "error.spi.connection.size";
+
+ public ConnectionSizeLimitException () {
+ super();
+ }
+
+ public ConnectionSizeLimitException (String url, int sizeLimit, Throwable cause) {
+ super(url, cause);
+ mMessageKey = CONNECTION_SIZE_KEY;
+ mMessageParams = new Object[]{mUrl, String.valueOf(sizeLimit)};
+ }
+}
diff --git a/src/com/sun/apoc/spi/IllegalAccessException.java b/src/com/sun/apoc/spi/IllegalAccessException.java
new file mode 100644
index 0000000..eb3f68f
--- /dev/null
+++ b/src/com/sun/apoc/spi/IllegalAccessException.java
@@ -0,0 +1,46 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class IllegalAccessException extends SPIException {
+
+ public IllegalAccessException () {
+ super();
+ }
+
+ public IllegalAccessException (Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/com/sun/apoc/spi/IllegalAssignmentException.java b/src/com/sun/apoc/spi/IllegalAssignmentException.java
new file mode 100644
index 0000000..bb52eab
--- /dev/null
+++ b/src/com/sun/apoc/spi/IllegalAssignmentException.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class IllegalAssignmentException extends SPIException {
+
+ private static final String ASSIGNMENT_KEY =
+ "error.spi.assignment.illegal";
+
+ protected String mApplicability = null;
+ protected String mEntityName = null;
+
+ public IllegalAssignmentException () {
+ super();
+ }
+
+ public IllegalAssignmentException (String applicability,
+ String entityName) {
+ super();
+ mApplicability = applicability;
+ mEntityName = entityName;
+ mMessageKey = ASSIGNMENT_KEY;
+ mMessageParams = new Object[]{mApplicability, entityName};
+ }
+
+ public String getApplicability() { return mApplicability; }
+ public String getEntityName() { return mEntityName; }
+}
diff --git a/src/com/sun/apoc/spi/IllegalReadException.java b/src/com/sun/apoc/spi/IllegalReadException.java
new file mode 100644
index 0000000..3492e14
--- /dev/null
+++ b/src/com/sun/apoc/spi/IllegalReadException.java
@@ -0,0 +1,77 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class IllegalReadException extends IllegalAccessException {
+
+ private static final String READ_KEY =
+ "error.spi.access.illegal.read";
+ public static final String LDAP_READ_KEY =
+ "error.spi.access.illegal.read.ldap";
+ public static final String LDAP_SIZE_READ_KEY =
+ "error.spi.access.illegal.read.ldap.size";
+ public static final String FILE_READ_KEY =
+ "error.spi.access.illegal.read.file";
+ public static final String FILE_NAME_READ_KEY =
+ "error.spi.access.illegal.read.file.name";
+
+ public IllegalReadException () {
+ super();
+ mMessageKey = READ_KEY;
+ }
+
+ public IllegalReadException (String messageKey) {
+ super();
+ mMessageKey = messageKey;
+ }
+
+ public IllegalReadException (String messageKey, Throwable cause) {
+ super(cause);
+ mMessageKey = messageKey;
+ }
+
+ public IllegalReadException (String messageKey, String filename) {
+ super();
+ mMessageKey = messageKey;
+ mMessageParams = new Object[]{filename};
+ }
+
+ public IllegalReadException (String messageKey, String filename,
+ Throwable cause) {
+ super(cause);
+ mMessageKey = messageKey;
+ mMessageParams = new Object[]{filename};
+ }
+}
diff --git a/src/com/sun/apoc/spi/IllegalWriteException.java b/src/com/sun/apoc/spi/IllegalWriteException.java
new file mode 100644
index 0000000..b6ccef6
--- /dev/null
+++ b/src/com/sun/apoc/spi/IllegalWriteException.java
@@ -0,0 +1,68 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class IllegalWriteException extends IllegalAccessException {
+
+ private static final String WRITE_KEY =
+ "error.spi.access.illegal.write";
+ public static final String LDAP_WRITE_KEY =
+ "error.spi.access.illegal.write.ldap";
+ public static final String FILE_WRITE_KEY =
+ "error.spi.access.illegal.write.file";
+ public static final String FILE_CREATE_KEY =
+ "error.spi.access.illegal.write.file.create";
+
+ public IllegalWriteException () {
+ super();
+ mMessageKey = WRITE_KEY;
+ }
+
+ public IllegalWriteException (String messageKey) {
+ super();
+ mMessageKey = messageKey;
+ }
+
+ public IllegalWriteException (String messageKey, Throwable cause) {
+ super(cause);
+ mMessageKey = messageKey;
+ }
+
+ public IllegalWriteException (String messageKey, String filename) {
+ super();
+ mMessageKey = messageKey;
+ mMessageParams = new Object[]{filename};
+ }
+}
diff --git a/src/com/sun/apoc/spi/InterruptedConnectionException.java b/src/com/sun/apoc/spi/InterruptedConnectionException.java
new file mode 100644
index 0000000..f15b742
--- /dev/null
+++ b/src/com/sun/apoc/spi/InterruptedConnectionException.java
@@ -0,0 +1,50 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class InterruptedConnectionException extends ConnectionException {
+
+ private static final String INTERRUPTED_CONNECTION_KEY =
+ "error.spi.connection.interrupted";
+
+ public InterruptedConnectionException () {
+ super();
+ }
+
+ public InterruptedConnectionException (String url, Throwable cause) {
+ super(url, cause);
+ mMessageKey = INTERRUPTED_CONNECTION_KEY;
+ }
+}
diff --git a/src/com/sun/apoc/spi/Makefile.am b/src/com/sun/apoc/spi/Makefile.am
new file mode 100644
index 0000000..34e56be
--- /dev/null
+++ b/src/com/sun/apoc/spi/Makefile.am
@@ -0,0 +1,7 @@
+ANT = @ANT@
+
+all:
+ $(ANT)
+
+clean-local:
+ $(ANT) -q clean
diff --git a/src/com/sun/apoc/spi/OpenConnectionException.java b/src/com/sun/apoc/spi/OpenConnectionException.java
new file mode 100644
index 0000000..701e41b
--- /dev/null
+++ b/src/com/sun/apoc/spi/OpenConnectionException.java
@@ -0,0 +1,50 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class OpenConnectionException extends ConnectionException {
+
+ private static final String OPEN_CONNECTION_KEY =
+ "error.spi.connection.open";
+
+ public OpenConnectionException () {
+ super();
+ }
+
+ public OpenConnectionException (String url, Throwable cause) {
+ super(url, cause);
+ mMessageKey = OPEN_CONNECTION_KEY;
+ }
+}
diff --git a/src/com/sun/apoc/spi/PolicyManager.java b/src/com/sun/apoc/spi/PolicyManager.java
new file mode 100644
index 0000000..9dfd39c
--- /dev/null
+++ b/src/com/sun/apoc/spi/PolicyManager.java
@@ -0,0 +1,274 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi ;
+
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.EntityTreeProvider;
+import java.util.HashMap ;
+import java.util.Hashtable ;
+import java.util.Map ;
+
+import com.sun.apoc.spi.environment.EnvironmentMgr ;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileProvider;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Main access point to the policy management objects, basically maps to an
+ * instance of the meta-configuration file.
+ */
+public class PolicyManager {
+ /** Meta-configuration of the policy management. */
+ private EnvironmentMgr mEnvironment = null ;
+ /** Ordered list of sources (by order of use). */
+ private PolicySource [] mSources = null ;
+ /** Map between source names and sources (for access to source by type). */
+ private Map mSourcesByName = new HashMap() ;
+
+
+ /**
+ * Constructor from a hashtable providing values for the meta-configuration
+ * of the policy access (location of entity trees, storage of profiles and
+ * their assignments).
+ *
+ * @param aBootstrapInfo hashtable with bootstrap information
+ * @throws SPIException if an error occurs.
+ */
+ public PolicyManager(Hashtable aBootstrapInfo) throws SPIException {
+ mEnvironment = new EnvironmentMgr(aBootstrapInfo) ;
+ mEnvironment.checkEnvironment();
+ String [] sources = mEnvironment.getSources() ;
+
+ mSources = new PolicySource [sources.length] ;
+ for (int i = 0 ; i < sources.length ; ++ i) {
+ mSources [i] = new PolicySource(sources [i], mEnvironment) ;
+ mSourcesByName.put(sources [i], mSources [i]) ;
+ }
+ }
+
+ /**
+ * Returns the entity provider for a given source.
+ *
+ * @param aSource source name
+ * @return entity provider or null if it doesn't exist
+ */
+ public EntityTreeProvider getEntityProvider(String aSource) {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+
+ return source != null ? source.getEntityProvider() : null ;
+ }
+
+ /**
+ * Returns the assignment provider for a given source.
+ *
+ * @param aSource source name
+ * @return assignment provider or null if it doesn't exist
+ */
+ public AssignmentProvider getAssignmentProvider(String aSource) {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+
+ return source != null ? source.getAssignmentProvider() : null ;
+ }
+
+ /**
+ * Returns the profile provider for a given source.
+ *
+ * @param aSource source name
+ * @return profile provider or null if it doesn't exist
+ */
+ public ProfileProvider getProfileProvider(String aSource) {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+
+ return source != null ? source.getProfileProvider() : null ;
+ }
+
+ /**
+ * Returns the root entity for a given source.
+ *
+ * @param aSource source name
+ * @return root entity or null if it doesn't exist
+ */
+ public Entity getRootEntity(String aSource) throws SPIException {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+
+ return source != null ? source.getRoot() : null ;
+ }
+
+ /**
+ * Returns the entity with given id for a given source.
+ *
+ * @param aSource source name
+ * @param aId entity id
+ * @return entity or null if it doesn't exist
+ */
+ public Entity getEntity(String aSource, String aId) throws SPIException {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+
+ return source != null ? source.getEntity(aId) : null ;
+ }
+
+ /**
+ * Returns the entity with given id from all sources.
+ *
+ * @param aId entity id
+ * @return entity or null if it doesn't exist
+ */
+ public Entity getEntity(String aId) throws SPIException {
+ Entity sEntity = null;
+ for (int i = 0 ; i < mSources.length && sEntity == null; ++ i) {
+ sEntity = getEntity(mSources[i].getName(), aId);
+ }
+
+ return sEntity ;
+ }
+
+ /**
+ * Returns the profile with given id for a given source.
+ *
+ * @param aSource source name
+ * @param aId profile id
+ * @return profile or null if it doesn't exist
+ */
+ public Profile getProfile(String aSource, String aId) throws SPIException {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+ ProfileProvider provider = source.getProfileProvider();
+ Profile profile = null;
+ if (provider != null) {
+ try {
+ profile = provider.getProfile(aId);
+ if (profile != null) {
+ if (!profile.getApplicability().getStringValue().equals(source.getName())) {
+ profile = null;
+ }
+ }
+ } catch (SPIException e) {
+ }
+ }
+ return profile;
+ }
+
+ /**
+ * Returns the profile with given id from all sources.
+ *
+ * @param aId profile id
+ * @return profile or null if it doesn't exist
+ */
+ public Profile getProfile(String aId) throws SPIException {
+ Profile sProfile = null;
+ for (int i = 0 ; i < mSources.length && sProfile == null; ++ i) {
+ sProfile = getProfile(mSources[i].getName(), aId);
+ }
+ return sProfile ;
+ }
+
+ /**
+ * Returns all the <code>Profile</code>s.
+ *
+ * @return an Iterator over all the <code>Profile</code> objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getAllProfiles() throws SPIException {
+ ArrayList sProfileList = new ArrayList();
+ for (int i = 0 ; i < mSources.length; ++ i) {
+ ProfileProvider sProvider = mSources[i].getProfileProvider();
+ Iterator it = sProvider.getAllProfiles();
+ while (it.hasNext()) {
+ Profile sProfile = (Profile)it.next();
+ // if (!sProfileList.contains(sProfile)) {
+ sProfileList.add(sProfile);
+ // }
+ }
+ }
+ return sProfileList.iterator() ;
+ }
+
+ /**
+ * Returns the profile repository with given id for a given source.
+ *
+ * @param aSource source name
+ * @param aId profile repository id
+ * @return profile repository or null if it doesn't exist
+ */
+ public ProfileRepository getProfileRepository(String aSource, String aId) throws SPIException {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+ ProfileProvider provider = source.getProfileProvider();
+ return provider != null ? provider.getProfileRepository(aId) : null ;
+ }
+
+ /**
+ * Returns the default profile repository for a given source.
+ *
+ * @param aSource source name
+ * @return default profile repository or null if it doesn't exist
+ */
+ public ProfileRepository getDefaultProfileRepository(String aSource) throws SPIException {
+ PolicySource source = (PolicySource)mSourcesByName.get(aSource) ;
+ ProfileProvider provider = source.getProfileProvider();
+ return provider != null ? provider.getDefaultProfileRepository() : null ;
+ }
+
+ /**
+ * Returns a copy of the environment table used to establish this object.
+ *
+ * @return <code>Hashtable</code> containing environmental settings
+ */
+ public Hashtable getEnvironment() throws SPIException {
+ return mEnvironment.getEnvironment();
+ }
+
+ /**
+ * Returns the array of policy source names used by this policy manager instance.
+ *
+ * @return <code>Hashtable</code> containing environmental settings
+ */
+ public String[] getSources() throws SPIException {
+ return mEnvironment.getSources();
+ }
+
+ /**
+ * Closes the sessions on the different providers
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void close() throws SPIException {
+ for (int i = 0 ; i < mSources.length ; ++ i) {
+ mSources[i].close();
+ }
+ }
+}
+
diff --git a/src/com/sun/apoc/spi/PolicySource.java b/src/com/sun/apoc/spi/PolicySource.java
new file mode 100644
index 0000000..5b5137a
--- /dev/null
+++ b/src/com/sun/apoc/spi/PolicySource.java
@@ -0,0 +1,297 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi ;
+
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.EntityTreeProvider ;
+import com.sun.apoc.spi.environment.EnvironmentMgr;
+import com.sun.apoc.spi.file.FileProviderFactory;
+import com.sun.apoc.spi.ldap.LdapProviderFactory;
+import com.sun.apoc.spi.profiles.ProfileProvider ;
+import java.lang.reflect.Constructor;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Class representing a policy source, i.e an entity provider, a profile
+ * provider and an assignment provider binding entities to profiles.
+ */
+public class PolicySource {
+ /** Name of the source. */
+ private String mName = null ;
+ /** General environment. */
+ private EnvironmentMgr mEnvironment = null ;
+ /** Entity provider. */
+ private EntityTreeProvider mEntities = null ;
+ /** Profile provider. */
+ private ProfileProvider mProfiles = null ;
+ /** Assignment provider. */
+ private AssignmentProvider mAssignments = null ;
+ /** Failed URLs */
+ private Set mFailedURLs;
+
+ /**
+ * Constructor from environment and name. Based on the name provided,
+ * will extract from the environment the provider informations.
+ *
+ * @param aName source name
+ * @param aEnvironment bootstrap environment
+ * @throws SPIException if an error occurs.
+ */
+ public PolicySource(String aName,
+ EnvironmentMgr aEnvironment) throws SPIException {
+ mName = aName ;
+ mEnvironment = aEnvironment ;
+ mFailedURLs = new HashSet();
+ mEntities = (EntityTreeProvider) getProvider(EntityTreeProvider.class) ;
+ mProfiles = (ProfileProvider) getProvider(ProfileProvider.class) ;
+ mAssignments =
+ (AssignmentProvider) getProvider(AssignmentProvider.class) ;
+ }
+
+ /**
+ * Returns a copy of the environment table used to establish this object.
+ *
+ * @return <code>Hashtable</code> containing environmental settings
+ */
+ public Hashtable getEnvironment() {
+ return mEnvironment.getEnvironment();
+ }
+
+ /**
+ * Returns root entity for this <code>PolicySource</code>.
+ *
+ * @return <code>Entity</code> that is the root for this source
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getRoot() throws SPIException {
+ return mEntities.getRootEntity();
+ }
+
+ /**
+ * Returns the entity with the given EntityId in this <code>PolicySource</code>.
+ *
+ * @param aId the EntityId to look for
+ * @return <code>Entity</code> that is the root for this source
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity(String aId) throws SPIException {
+ return mEntities.getEntity(aId);
+ }
+
+ /**
+ * Returns the EntityProvider object for this <code>PolicySource</code>.
+ *
+ * @return <code>EntityProvider</code> for this source
+ */
+ public EntityTreeProvider getEntityProvider() {
+ return mEntities;
+ }
+
+ /**
+ * Returns the AssignmentProvider object for this <code>PolicySource</code>.
+ *
+ * @return <code>AssignmentProvider</code> for this source
+ */
+ public AssignmentProvider getAssignmentProvider() {
+ return mAssignments;
+ }
+
+ /**
+ * Returns the ProfileProvider object for this <code>PolicySource</code>.
+ *
+ * @return <code>ProfileProvider</code> for this source
+ */
+ public ProfileProvider getProfileProvider() {
+ return mProfiles;
+ }
+
+ /**
+ * Returns the name for this policy <code>PolicySource</code>.
+ *
+ * @return name of this policy source
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Closes the sessions on the different providers
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void close() throws SPIException {
+ HashSet providerSet = new HashSet();
+ if (mEntities != null) {
+ providerSet.add(mEntities);
+ }
+ if (mAssignments != null) {
+ providerSet.add(mAssignments);
+ }
+ if (mProfiles != null) {
+ providerSet.add(mProfiles);
+ }
+ Iterator iterProviderSet = providerSet.iterator();
+ while (iterProviderSet.hasNext()) {
+ ((Provider)iterProviderSet.next()).close();
+ }
+ }
+
+ /**
+ * Indicates if the url has been referenced as a failing URL
+ * by a previous connection attempt
+ * @param url the URL to check
+ * @return true if it is a failed URL
+ */
+ public synchronized boolean isFailedURL(String url) {
+ return mFailedURLs.contains(url);
+ }
+
+ /**
+ * Add the url in the list referencing the failing URLs
+ * @param url failing url to reference
+ */
+ public synchronized void addFailedURL(String url) {
+ if (!isFailedURL(url)) {
+ mFailedURLs.add(url);
+ }
+ }
+
+ /**
+ * gets the object stored under the key url
+ * and managing the connection to that url
+ *
+ * @param stringURL the string representing the URL
+ * for the connection
+ * @return an object managing the connection
+ * or null if one does not exist
+ */
+ public synchronized Object getConnectionHandler(String stringURL) {
+ return mEnvironment.getConnectionHandler(stringURL);
+ }
+
+ /**
+ * stores a connection handler under the key url
+ *
+ * @param stringURL the string representing the URL
+ * @param connection the object managing the connection
+ */
+ public synchronized void setConnectionHandler(String stringURL, Object connection) {
+ mEnvironment.setConnectionHandler(stringURL, connection);
+ }
+
+ /**
+ * Gets the provider associated with a particular type of data (entities,
+ * assignments or profiles). Uses the environment to find either a class
+ * name or a list of URLs describing the provider parameters. The only
+ * supported schemes for providers are LDAP or file-based ones, the actual
+ * generation of the appropriate provider is delegated to a factory in the
+ * backend-specific packages.
+ *
+ * @param aProviderClass expected provider class
+ * @return provider instance
+ * @throws SPIException if an error occurs.
+ */
+ private Provider getProvider(Class aProviderClass) throws SPIException {
+ Provider retCode = null ;
+ String providerClass = mEnvironment.getProviderClass(mName,
+ aProviderClass) ;
+
+ if (providerClass != null) { return loadProvider(providerClass) ; }
+ String [] urls = mEnvironment.getProviderURLs(mName, aProviderClass) ;
+
+ for (int i = 0 ; retCode == null && i < urls.length ; ++ i) {
+ String url = urls [i] ;
+
+ if (isFailedURL(url)) { continue ; }
+ try {
+ String protocol = url.substring(0, url.indexOf(":"));
+ if (mEnvironment.isLdapProtocol(protocol)) {
+ retCode = LdapProviderFactory.get(url, aProviderClass,
+ this) ;
+ if (retCode != null) { retCode.open(); }
+ }
+ else if (mEnvironment.isFileProtocol(protocol)) {
+ retCode = FileProviderFactory.get(url, aProviderClass,
+ this) ;
+ if (retCode != null) { retCode.open(); }
+ }
+ else {
+ // Unsupported type, forget about this one.
+ continue ;
+ }
+ }
+ catch (SPIException exception) {
+ if (i == urls.length -1) {
+ // They've all failed, not good.
+ throw exception ;
+ }
+ // Let's not repeat the same mistake twice.
+ addFailedURL(url) ;
+ }
+ }
+ return retCode ;
+ }
+
+ /**
+ * Loads a provider from its class name. It's expected said class has a
+ * constructor taking a PolicySource as its sole parameter.
+ *
+ * @param aProviderClass provider class name
+ * @return provider instance
+ * @throws SPIException if the class cannot be loaded or its constructor
+ * fails to execute.
+ */
+ private Provider loadProvider(String aProviderClass) throws SPIException {
+ try {
+ Class providerClass =
+ this.getClass().getClassLoader().loadClass(aProviderClass) ;
+ Class [] parameterClasses = { PolicySource.class } ;
+ Constructor providerConstructor =
+ providerClass.getConstructor(parameterClasses) ;
+ Object [] parameters = { this } ;
+
+ return (Provider)providerConstructor.newInstance(parameters) ;
+ }
+ catch (Exception exception) {
+ throw new ProviderLoadingException(aProviderClass, exception) ;
+ }
+ }
+
+}
+
diff --git a/src/com/sun/apoc/spi/Provider.java b/src/com/sun/apoc/spi/Provider.java
new file mode 100644
index 0000000..1fac052
--- /dev/null
+++ b/src/com/sun/apoc/spi/Provider.java
@@ -0,0 +1,61 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+/**
+ * Common interface for object providers.
+ * Allows to open and close the object datasource.
+ *
+ */
+public interface Provider {
+
+ /**
+ * Opens the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws OpenConnectionException if connection error occurs
+ * @throws CloseConnectionException if connection error occurs
+ * @throws AuthenticateException if connection error occurs
+ */
+ public void open() throws SPIException;
+
+ /**
+ * Closes the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws CloseConnectionException if connection error occurs
+ */
+ public void close() throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/ProviderLoadingException.java b/src/com/sun/apoc/spi/ProviderLoadingException.java
new file mode 100644
index 0000000..d6fb7bb
--- /dev/null
+++ b/src/com/sun/apoc/spi/ProviderLoadingException.java
@@ -0,0 +1,52 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+public class ProviderLoadingException extends SPIException {
+
+ private static final String PROVIDER_LOADING_KEY =
+ "error.spi.provider.loading";
+
+ protected String mClassName = null;
+
+ public ProviderLoadingException(String className, Throwable cause) {
+ super(cause);
+ mClassName = className;
+ mMessageKey = PROVIDER_LOADING_KEY;
+ mMessageParams = new Object[]{mClassName};
+ }
+
+ public String getProviderClassPath() { return mClassName; }
+}
diff --git a/src/com/sun/apoc/spi/SPIException.java b/src/com/sun/apoc/spi/SPIException.java
new file mode 100644
index 0000000..29e0113
--- /dev/null
+++ b/src/com/sun/apoc/spi/SPIException.java
@@ -0,0 +1,369 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Common Exception class for the registry objects.
+ */
+public class SPIException extends Exception
+{
+ /** string that maps to localized error message */
+ private String mLocalizedErrorMessageCode = ERROR_OCCURRED;
+ /** Static string for codes that map to localized error strings
+ * @deprecated
+ * */
+ public static final String ERROR_OCCURRED = "error.occurred";
+ /**@deprecated */
+ public static final String ERROR_OPEN_CONNECTION =
+ "error.open.connection";
+ /**@deprecated */
+ public static final String ERROR_CLOSE_CONNECTION =
+ "error.close.connection";
+ /**@deprecated */
+ public static final String ERROR_USER_INVALID = "error.user.invalid";
+ /**@deprecated */
+ public static final String ERROR_HOST_INVALID = "error.host.invalid";
+ /**@deprecated */
+ public static final String ERROR_UNSUPPORTED_DATASTORE =
+ "error.unsupported.datastore";
+ /**@deprecated */
+ public static final String ERROR_APPLICATION_INIT =
+ "error.application.initialize";
+ /**@deprecated */
+ public static final String ERROR_BOOTSTRAP_INCOMPLETE =
+ "error.bootstrap.incomplete";
+ /**@deprecated */
+ public static final String ERROR_BOOTSTRAP_UNAVAILABLE =
+ "error.bootstrap.unavailable";
+ /**@deprecated */
+ public static final String ERROR_LDAP_BOOTSTRAP =
+ "error.ldap.bootstrap";
+ /**@deprecated */
+ public static final String ERROR_ORG_SETTINGS = "error.org.settings";
+ /**@deprecated */
+ public static final String ERROR_DOMAIN_SETTINGS = "error.domain.settings";
+ /**@deprecated */
+ public static final String ERROR_ROLE_SETTINGS = "error.role.settings";
+ /**@deprecated */
+ public static final String ERROR_USER_SETTINGS = "error.user.settings";
+ /**@deprecated */
+ public static final String ERROR_HOST_SETTINGS = "error.host.settings";
+ /**@deprecated */
+ public static final String ERROR_CREATE_PARSER = "error.create.parser";
+ /**@deprecated */
+ public static final String ERROR_FILTER = "error.FILTER";
+ /**@deprecated */
+ public static final String ERROR_POLICY_READ = "error.policy.read";
+ /**@deprecated */
+ public static final String ERROR_POLICY_DATA_INVALID =
+ "error.policy.data.invalid";
+ /**@deprecated */
+ public static final String ERROR_POLICY_INVALID =
+ "error.policy.invalid";
+ /**@deprecated */
+ public static final String ERROR_PATH_INVALID =
+ "error.path.invalid";
+ /**@deprecated */
+ public static final String ERROR_USERPROFILE_ATTR =
+ "error.userprofile.attribute";
+ /**@deprecated */
+ public static final String ERROR_LOCALE_SUPPORT =
+ "error.locale.support";
+ /**@deprecated */
+ public static final String ERROR_LDAP_READ =
+ "error.ldap.read";
+ /**@deprecated */
+ public static final String ERROR_LDAP_WRITE =
+ "error.ldap.write";
+ /**@deprecated */
+ public static final String ERROR_LDAP_SEARCH =
+ "error.ldap.search";
+ /**@deprecated */
+ public static final String ERROR_LDAP_RESULTS_SIZE =
+ "error.ldap.results.size";
+ /**@deprecated */
+ public static final String ERROR_LDAP_PROFILE_CREATION =
+ "error.ldap.profile.creation";
+ /**@deprecated */
+ public static final String ERROR_LDAP_PROFILE_DELETION =
+ "error.ldap.profile.deletion";
+ /**@deprecated */
+ public static final String ERROR_LDAP_PROFILE_RENAME =
+ "error.ldap.profile.rename";
+ /**@deprecated */
+ public static final String ERROR_UNPROTECT_ITEM =
+ "error.unprotect.item";
+ /**@deprecated */
+ public static final String ERROR_READONLY_ITEM =
+ "error.readonly.item";
+ /**@deprecated */
+ public static final String ERROR_MANDATORY_SETTING =
+ "error.mandatory.setting";
+ /**@deprecated */
+ public static final String ERROR_MANDATORY_REMOVE =
+ "error.mandatory.remove";
+ /**@deprecated */
+ public static final String ERROR_COMPLY_CONSTRAINTS =
+ "error.comply.constraints";
+ /**@deprecated */
+ public static final String ERROR_NILLABLE_ITEM =
+ "error.nillable.item";
+ /**@deprecated */
+ public static final String ERROR_PRIORITY_EXISTS =
+ "error.profile.priority.exists";
+ /**@deprecated */
+ public static final String ERROR_PROFILE_NAME_EXISTS =
+ "error.profile.name.exists";
+ /**@deprecated */
+ public static final String ERROR_PROFILE_DOESNT_EXIST =
+ "error.profile.not.exists";
+ /**@deprecated */
+ public static final String ERROR_PRIORITIES_INCORRECT =
+ "error.priorities.incorrect";
+ /**@deprecated */
+ public static final String ERROR_PRIORITIES_INVALID =
+ "error.priorities.invalid";
+ /**@deprecated */
+ public static final String ERROR_EXPORT_PROFILE =
+ "error.export.profile";
+ /**@deprecated */
+ public static final String ERROR_IMPORT_PROFILE =
+ "error.import.profile";
+ /**@deprecated */
+ public static final String ERROR_EXPORT_PROFILE_DATA =
+ "error.export.profile.data";
+ /**@deprecated */
+ public static final String ERROR_IMPORT_PROFILE_DATA =
+ "error.import.profile.data";
+
+
+ /** Registry module where the exception occurred */
+ private String mModule = null ;
+ /** Qualified error code depending on the module */
+ private int mErrorCode = 0 ;
+
+ /**
+ * Only constructor. To avoid bogus, under-qualified
+ * exceptions, all members are required.
+ *
+ * @param aErrorMessage detailed exception message
+ * @param aLocalizedErrorMessageCode maps to localized error string
+ * @param aModule module where the exception happened
+ * @param aErrorCode qualified error code for the module
+ * @deprecated
+ */
+ public SPIException(String aErrorMessage,
+ String aLocalizedErrorMessageCode,
+ String aModule,
+ int aErrorCode) {
+ super(aErrorMessage) ;
+ mLocalizedErrorMessageCode = aLocalizedErrorMessageCode;
+ mModule = aModule ;
+ mErrorCode = aErrorCode ;
+ }
+
+ /**
+ * Returns the string that maps to the localized error message
+ * in the resources file.
+ *
+ * @return code that maps to error message in localization
+ * database
+ * @deprecated
+ */
+ public String getLocalizedErrorMessageCode() {
+ return mLocalizedErrorMessageCode ;
+ }
+
+ /**
+ * Provides the name of the module where the exception occurred.
+ *
+ * @return module name
+ * @deprecated
+ */
+ public String getModule() { return mModule ; }
+
+ /**
+ * Provides the qualified error code depending on the module.
+ *
+ * @return error code
+ * @deprecated
+ */
+ public int getErrorCode() { return mErrorCode ; }
+
+ // new stuff
+ private static final String RESOURCE_BUNDLE =
+ "com.sun.apoc.spi.resources.SPIErrors";
+ private static final String DEFAULT_KEY =
+ "error.spi.default";
+ protected String mMessageKey = null;
+ protected Object[] mMessageParams = null;
+
+ /**
+ * Constructs a new SPIException with null as its detail message.
+ */
+ public SPIException() {
+ super();
+ mMessageKey = DEFAULT_KEY;
+ }
+
+ /**
+ * Constructs a new SPIException which detail message will
+ * be retrieved in the error message ressource bundles
+ * using the messageKey and messageParams if any.
+ *
+ * @param messageKey the key to retrieve the SPIException
+ * message in the error message ressource
+ * bundles
+ * @param messageParams objects to replace corresponding patterns
+ * in the message
+ */
+ public SPIException (String messageKey, Object[] messageParams) {
+ mMessageKey = messageKey;
+ mMessageParams = messageParams;
+ }
+
+ /**
+ * Constructs a new SPIException which detail message will
+ * be retrieved in the error message ressource bundles
+ * using the messageKey and messageParams if any.
+ *
+ * @param messageKey the key to retrieve the SPIException
+ * message in the error message ressource
+ * bundles
+ * @param messageParams objects to replace corresponding patterns
+ * in the message
+ * @param cause the cause (which is saved for later retrieval
+ * by the Throwable.getCause() method).
+ * (A null value is permitted, and indicates
+ * that the cause is nonexistent or unknown.)
+ */
+ public SPIException (String messageKey, Object[] messageParams,
+ Throwable cause) {
+ super(cause);
+ mMessageKey = messageKey;
+ mMessageParams = messageParams;
+ }
+
+ /**
+ * Constructs a new SPIException with the specified cause
+ *
+ * @param cause the cause (which is saved for later retrieval
+ * by the Throwable.getCause() method).
+ * (A null value is permitted, and indicates
+ * that the cause is nonexistent or unknown.)
+ */
+ public SPIException (Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Returns the localized detail message string
+ * of this SPIException, with the locale provided.
+ *
+ * @param locale Locale to use to retrieve the message
+ * in the resource bundles.
+ * @return the localized detail message string
+ * of this SPIException instance
+ * (which may be null if the messageKey was
+ * null in the constructor or not found
+ * in the resource bundle).
+ */
+ public String getLocalizedMessage(Locale locale) {
+ Locale localeToUse = locale;
+ if (localeToUse == null) {
+ localeToUse = Locale.getDefault();
+ }
+ String message = null;
+ if (mMessageKey != null) {
+ // get the message from the resource bundle
+ ResourceBundle resBundle = ResourceBundle.getBundle(
+ RESOURCE_BUNDLE, locale);
+ message = resBundle.getString(mMessageKey);
+ if (mMessageParams != null) {
+ // insert params in message
+ MessageFormat formatter = new MessageFormat(message,
+ locale);
+ message = formatter.format(mMessageParams).toString();
+ }
+ }
+ return message;
+ }
+
+ /**
+ * Returns the localized detail message string
+ * of this SPIException, with the default Locale.
+ *
+ * @return the localized detail message string
+ * of this SPIException instance
+ * (which may be null if the messageKey was
+ * null in the constructor or not found
+ * in the resource bundle).
+ */
+ public String getLocalizedMessage() {
+ Locale locale = Locale.getDefault();
+ return getLocalizedMessage(locale);
+ }
+
+ /**
+ * Returns the localized detail message string
+ * of this SPIException, with the default Locale.
+ *
+ * @return the localized detail message string
+ * of this SPIException instance
+ * (which may be null if the messageKey was
+ * null in the constructor or not found
+ * in the resource bundle).
+ */
+ public String getMessage() {
+ return getLocalizedMessage();
+ }
+
+ private String getDebugMessage() {
+ String message = "";
+ Throwable cause = this.getCause();
+ if (cause != null) {
+ message += "\ncause:"+cause.toString();
+ }
+ StackTraceElement[] stack = this.getStackTrace();
+ for (int i=0; i<stack.length; i++) {
+ message+="\n"+stack[i].toString();
+ }
+ return message;
+ }
+}
diff --git a/src/com/sun/apoc/spi/build.xml.in b/src/com/sun/apoc/spi/build.xml.in
new file mode 100644
index 0000000..9c2fa90
--- /dev/null
+++ b/src/com/sun/apoc/spi/build.xml.in
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+#*************************************************************************
+#*
+#* $RCSfile: build.xml,v $
+#*
+#* last change $Author: cm122549 $ $Date: 2007/01/18 12:55:19 $
+#* $Revision: 1.12 $
+#*
+#* Copyright 2004, Sun Microsystems, Inc. All Rights Reserved.
+#*
+#*************************************************************************
+-->
+<project name="apoc_spi" default="main" basedir="../../../../../">
+
+ <property name="jarname" value="spi.jar"/>
+ <property name="package" value="com/sun/apoc/spi"/>
+
+ <!-- The name of the out/dist directory (e.g. "out" or "unxsols4.pro") -->
+ <property name="inpath" value="build"/>
+ <property name="build.dir" value="${inpath}"/>
+ <property name="build.class" value="${build.dir}/class"/>
+ <!--property name="build.doc" value="${build.dir}/doc/spi"/-->
+
+ <path id="classpath">
+ <pathelement location="@LDAPJDK@"/>
+ </path>
+
+ <target name="prepare">
+ <mkdir dir="${build.dir}"/>
+ <mkdir dir="${build.class}"/>
+ </target>
+
+ <target name="compile" depends="prepare">
+ <javac srcdir="src"
+ destdir="${build.class}"
+ classpathref="classpath"
+ debug="${debug}">
+ <include name="${package}/**/*.java"/>
+ </javac>
+ <copy todir="${build.class}">
+ <fileset dir="src" defaultexcludes="yes">
+ <include name="${package}/**/*.properties"/>
+ </fileset>
+ </copy>
+ <copy file="src/${package}/copyright.txt" todir="${build.class}/${package}"/>
+ </target>
+
+ <target name="jar" depends="compile">
+ <jar jarfile="${build.class}/${jarname}"
+ basedir="${build.class}"
+ includes="${package}/**">
+ <manifest>
+ <attribute name="Class-Path" value="@LDAPJDK@"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="main" depends="jar"/>
+
+ <target name="clean">
+ <delete file="${build.class}/${jarname}"/>
+ <delete dir="${build.class}/${package}"/>
+ </target>
+
+ <!--target name="preparedoc">
+ <delete dir="${build.doc}"/>
+ <mkdir dir="${build.dir}"/>
+ <mkdir dir="${build.doc}"/>
+ </target-->
+
+ <!--target name="compiledoc">
+ <javadoc
+ destdir="${build.doc}"
+ public="true"
+ author="false"
+ version="false"
+ use="true"
+ windowtitle="APOC SPI">
+
+ <fileset dir="src" defaultexcludes="yes">
+ <include name="${package}/AssignmentProvider.java" />
+ <include name="${package}/AuthenticationException.java" />
+ <include name="${package}/CloseConnectionException.java" />
+ <include name="${package}/ConnectionException.java" />
+ <include name="${package}/ConnectionSizeLimitException.java" />
+ <include name="${package}/IllegalAssignmentException.java" />
+ <include name="${package}/IllegalAccessException.java" />
+ <include name="${package}/IllegalReadException.java" />
+ <include name="${package}/IllegalWriteException.java" />
+ <include name="${package}/InterruptedConnectionException.java" />
+ <include name="${package}/OpenConnectionException.java" />
+ <include name="${package}/PolicyMgr.java" />
+ <include name="${package}/PolicyMgrFactory.java" />
+ <include name="${package}/PolicyMgrFactoryImpl.java" />
+ <include name="${package}/Provider.java" />
+ <include name="${package}/ProviderLoadingException.java" />
+ <include name="${package}/SPIException.java" />
+
+ <include name="${package}/cfgtree/DataType.java" />
+ <include name="${package}/cfgtree/ElementCopyException.java" />
+ <include name="${package}/cfgtree/InvalidDataTypeException.java" />
+ <include name="${package}/cfgtree/MandatoryElementException.java" />
+ <include name="${package}/cfgtree/PolicyTree.java" />
+ <include name="${package}/cfgtree/PolicyTreeConverter.java" />
+ <include name="${package}/cfgtree/PolicyTreeException.java" />
+ <include name="${package}/cfgtree/PolicyTreeFactory.java" />
+ <include name="${package}/cfgtree/ProtectedElement.java" />
+ <include name="${package}/cfgtree/ReadOnlyElementException.java" />
+ <include name="${package}/cfgtree/ReadWritePolicyTreeFactory.java" />
+ <include name="${package}/cfgtree/XMLPolicyTreeException.java" />
+
+ <include name="${package}/cfgtree/policynode/InvalidPolicyNodeException.java" />
+ <include name="${package}/cfgtree/policynode/InvalidPolicyNodeNameException.java" />
+ <include name="${package}/cfgtree/policynode/MergedPolicyNode.java" />
+ <include name="${package}/cfgtree/policynode/PolicyNode.java" />
+ <include name="${package}/cfgtree/policynode/PolicyNodeException.java" />
+
+ <include name="${package}/cfgtree/property/InvalidPropertyException.java" />
+ <include name="${package}/cfgtree/property/InvalidPropertyNameException.java" />
+ <include name="${package}/cfgtree/property/MergedProperty.java" />
+ <include name="${package}/cfgtree/property/Property.java" />
+ <include name="${package}/cfgtree/property/PropertyException.java" />
+
+ <include name="${package}/entities/Domain.java" />
+ <include name="${package}/entities/DomainTreeProvider.java" />
+ <include name="${package}/entities/Entity.java" />
+ <include name="${package}/entities/EntityException.java" />
+ <include name="${package}/entities/EntityTreeProvider.java" />
+ <include name="${package}/entities/Host.java" />
+ <include name="${package}/entities/InvalidEntityIdException.java" />
+ <include name="${package}/entities/InvalidFilterException.java" />
+ <include name="${package}/entities/Leaf.java" />
+ <include name="${package}/entities/Node.java" />
+ <include name="${package}/entities/NoSuchEntityException.java" />
+ <include name="${package}/entities/Organization.java" />
+ <include name="${package}/entities/OrganizationTreeProvider.java" />
+ <include name="${package}/entities/Role.java" />
+ <include name="${package}/entities/User.java" />
+
+ <include name="${package}/environment/EnvironmentConstants.java" />
+ <include name="${package}/environment/EnvironmentException.java" />
+ <include name="${package}/environment/InvalidParameterException.java" />
+ <include name="${package}/environment/MissingParameterException.java" />
+ <include name="${package}/environment/ParameterException.java" />
+ <include name="${package}/environment/PasswordCodec.java" />
+ <include name="${package}/environment/RemoteEnvironmentException.java" />
+
+ <include name="${package}/policies/InvalidPolicyException.java" />
+ <include name="${package}/policies/MismatchPolicyException.java" />
+ <include name="${package}/policies/NoSuchPolicyException.java" />
+ <include name="${package}/policies/Policy.java" />
+ <include name="${package}/policies/PolicyException.java" />
+ <include name="${package}/policies/PolicyInfo.java" />
+
+ <include name="${package}/profiles/Applicability.java" />
+ <include name="${package}/profiles/InvalidDisplayNameException.java" />
+ <include name="${package}/profiles/InvalidPriorityException.java" />
+ <include name="${package}/profiles/InvalidProfileException.java" />
+ <include name="${package}/profiles/NullProfileException.java" />
+ <include name="${package}/profiles/Profile.java" />
+ <include name="${package}/profiles/ProfileException.java" />
+ <include name="${package}/profiles/ProfileProvider.java" />
+ <include name="${package}/profiles/ProfileRepository.java" />
+ <include name="${package}/profiles/ProfileStreamException.java" />
+ <include name="${package}/profiles/ProfileZipException.java" />
+ <include name="${package}/profiles/UnknownApplicabilityException.java" />
+ </fileset>
+
+ <doctitle><![CDATA[<h1>APOC Service Provider Interface</h1>]]></doctitle>
+ <bottom><![CDATA[<center><i>Copyright &#169; 2005 Sun Microsystems, Inc. All Rights Reserved.</i></center>]]></bottom>
+ </javadoc>
+ </target-->
+
+ <!--target name="zipdoc">
+ <zip destfile="${build.doc}/../apoc_spi-doc.zip"
+ basedir="${build.doc}"/>
+ </target-->
+
+ <!--target name="doc" depends="preparedoc, compiledoc, zipdoc"/-->
+</project>
diff --git a/src/com/sun/apoc/spi/cfgtree/ConfigElementImpl.java b/src/com/sun/apoc/spi/cfgtree/ConfigElementImpl.java
new file mode 100644
index 0000000..1209c44
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/ConfigElementImpl.java
@@ -0,0 +1,310 @@
+ /*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNode;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNodeImpl;
+import com.sun.apoc.spi.cfgtree.property.Property;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Abstract class for a configuration element.
+ *
+ */
+public abstract class ConfigElementImpl {
+
+ /** boolean indicating whether or not the element was added
+ by the toplevel profile policy */
+ protected boolean mIsAddedAtTopLayer = false;
+ /** boolean indicating whether or not an element is dynamic, that is,
+ an added element */
+ protected boolean mIsDynamic = false;
+ /** boolean indicating whether or not an element may be
+ removed or replaced */
+ protected boolean mIsMandatory = false;
+ /** Name of the element */
+ protected String mName;
+ /** int representing operation attribute value */
+ protected int mOperationType = OperationType.OP_UNKNOWN;
+ /** layer where mandatory attribute set to true */
+ protected Policy mOriginOfMandatory;
+ /** The package name */
+ protected String mPackage ;
+ /** Parent node */
+ protected PolicyNodeImpl mParent ;
+ /** The path to the element */
+ protected String mPath;
+ /** Policy tree object */
+ protected PolicyTreeImpl mPolicyTree;
+ /** Module name for exceptions */
+ private static final String MODULE = "ConfigElementImpl";
+
+
+ /**
+ * Used prior to removing a element to check if the element is
+ * mandatory, and if it is then an exception is thrown.
+ *
+ * @throws <code>SPIException</code> if element
+ * mandatory
+ */
+ public void checkIfMandatory() throws SPIException {
+ if (mIsMandatory) {
+ String elementType = "ProtectedElement";
+ if (this instanceof PolicyNode) {
+ elementType = "PolicyNode";
+ }
+ else if (this instanceof Property) {
+ elementType = "Property";
+ }
+ throw new MandatoryElementException(elementType, getName());
+ }
+ }
+
+ /**
+ * Copies this elements's settings to the element passed
+ * into the function.
+ *
+ * @param aNewElement the element to be changed
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public void copySettings(ConfigElementImpl aNewElement)
+ throws SPIException {
+ aNewElement.mIsAddedAtTopLayer = mIsAddedAtTopLayer;
+ aNewElement.mIsDynamic = mIsDynamic;
+ aNewElement.mIsMandatory = mIsMandatory;
+ aNewElement.mName = mName;
+ aNewElement.mOperationType = mOperationType;
+ aNewElement.mPackage = mPackage;
+ aNewElement.mPolicyTree = mPolicyTree;
+ aNewElement.mParent = mParent;
+ aNewElement.mPath = mPath;
+ aNewElement.mOriginOfMandatory = mOriginOfMandatory;
+ }
+
+ /**
+ * Returns the absolute path for this node.
+ *
+ * @return the absolute path
+ */
+ public String getAbsolutePath() { return mPath; }
+
+ /**
+ * Returns the name of the element.
+ *
+ * @return name of the element
+ */
+ public String getName() { return mName ; }
+
+
+ /**
+ * Returns the operation type.
+ *
+ * @return int representing operation type
+ */
+ public int getOperationType() {
+ return mOperationType ;
+ }
+
+ /**
+ * Gets the Policy where the element became
+ * mandatory.
+ *
+ * @return the Policy where the element became mandatory
+ */
+ public Policy getOriginOfMandatory() {
+ return mOriginOfMandatory;
+ }
+
+ /**
+ * Returns the package name.
+ *
+ * @return package name
+ */
+ public String getPackage() { return mPackage ; }
+
+ /**
+ * Returns the parent node.
+ *
+ * @return parent node, or null if there is none
+ */
+ public PolicyNode getParent() { return mParent ; }
+
+ /**
+ * Returns the <code>PolicyTreeImpl</code> object.
+ *
+ * @return policy tree object
+ */
+ public PolicyTreeImpl getPolicyTree() {
+ return mPolicyTree;
+ }
+
+ /**
+ * Returns a boolean indicating if the element has
+ * been modified.
+ *
+ * @return <code>true</code> if the element has been
+ * modified, otherwise <code>false</code>
+ */
+ public abstract boolean hasBeenModified() ;
+
+ /**
+ * Returns the setting of the flag indicating
+ * whether or not the element has been added at the
+ * toplevel layer.
+ *
+ * @return <code>true</code> if added
+ * at toplevel layer,
+ * otherwise <code>false</code>
+ */
+ public boolean isAddedAtTopLayer() { return mIsAddedAtTopLayer; }
+
+
+ /**
+ * Returns the setting of the mandatory flag, indicating
+ * whether or not the element may be removed or replaced.
+ *
+ * @return <code>true</code> if node is
+ * mandatory, otherwise <code>false</code>
+ */
+ public boolean isMandatory() {
+ return mIsMandatory;
+ }
+
+ /**
+ * Sets the flag to true, indicating that this property
+ * was added by the toplevel layer.
+ */
+ public void setAddedAtTopLayer() {
+ mIsAddedAtTopLayer = true;
+ }
+
+ /**
+ * Sets the dynamic flag to true.
+ */
+ public void setDynamic() {
+ mIsDynamic = true;
+ }
+
+
+ /**
+ * Sets the mandatory flag, without carrying out any checks on
+ * the node.
+ */
+ public void setMandatoryFlag() { mIsMandatory = true; }
+
+ /**
+ * Sets the name of the element from a string.
+ *
+ * @param aName name of the element
+ */
+ public void setName(String aName) { mName = aName ;}
+
+ /**
+ * Sets the operation type.
+ *
+ * @param aOperationType int representing operation type
+ */
+ public void setOperationType(int aOperationType) {
+ mOperationType = aOperationType;
+ }
+
+ /**
+ * Sets the layer where the mandatory
+ * flag was set.
+ *
+ * @param aSourceLayer layer where flag is set
+ */
+ public void setOriginOfMandatory(Policy aSourceLayer) {
+ mOriginOfMandatory = aSourceLayer;
+ }
+
+ /**
+ * Sets the package name.
+ *
+ * @param aPackage package name
+ */
+ public void setPackage(String aPackage) { mPackage = aPackage ; }
+
+
+ /**
+ * Sets the parent node.
+ *
+ * @param aParent parent node
+ */
+ public void setParent(PolicyNodeImpl aParent) { mParent = aParent ; }
+
+ /**
+ * Sets the element's path.
+ *
+ * @param aPath the element's path
+ */
+ public void setPath(String aPath) { mPath = aPath; }
+
+ /**
+ * Sets the PolicyTree object.
+ *
+ * @param aPolicyTree policy tree object
+ */
+ public void setPolicyTree(PolicyTreeImpl aPolicyTree) {
+ mPolicyTree = aPolicyTree ;
+ }
+
+ /**
+ * Returns a copy of the element.
+ *
+ * @return copy of the element
+ * @throws ElementCopyException if cannot create copy
+ */
+ public ConfigElementImpl shallowCopy() throws SPIException {
+ ConfigElementImpl returnCode = null;
+ try {
+ returnCode = (ConfigElementImpl)(getClass().newInstance());
+ } catch (Exception e) {
+ String elementType = "ProtectedElement";
+ if (this instanceof PolicyNode) {
+ elementType = "PolicyNode";
+ }
+ else if (this instanceof Property) {
+ elementType = "Property";
+ }
+ throw new ElementCopyException(elementType, getName(), e);
+ }
+ copySettings(returnCode);
+ return returnCode;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/DataType.java b/src/com/sun/apoc/spi/cfgtree/DataType.java
new file mode 100644
index 0000000..08c132e
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/DataType.java
@@ -0,0 +1,232 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.util.StringRangeEnum;
+
+/**
+ * Handles the possible types of the node values and
+ * their storage as integers.
+ *
+ */
+public class DataType extends StringRangeEnum
+{
+ protected static final int FIRST_LIST_ELEMENT = 8;
+ /** String type string */
+ public static final String STR_STRING = "xs:string" ;
+ /** Boolean type string */
+ public static final String STR_BOOLEAN = "xs:boolean" ;
+ /** Short type string */
+ public static final String STR_SHORT = "xs:short" ;
+ /** Int type string */
+ public static final String STR_INT = "xs:int" ;
+ /** Long type string */
+ public static final String STR_LONG = "xs:long" ;
+ /** Double type string */
+ public static final String STR_DOUBLE = "xs:double" ;
+ /** HexBinary type string */
+ public static final String STR_HEXBIN = "xs:hexBinary" ;
+ /** Any type string - where oor:any is used for any
+ basic type or derived list */
+ public static final String STR_ANY = "oor:any" ;
+ /** String list type */
+ public static final String STR_STRING_LIST = "oor:string-list" ;
+ /** Boolean list type */
+ public static final String STR_BOOLEAN_LIST = "oor:boolean-list" ;
+ /** Short list type */
+ public static final String STR_SHORT_LIST = "oor:short-list" ;
+ /** Int list type */
+ public static final String STR_INT_LIST = "oor:int-list" ;
+ /** Long list type */
+ public static final String STR_LONG_LIST = "oor:long-list" ;
+ /** Double list type */
+ public static final String STR_DOUBLE_LIST = "oor:double-list" ;
+ /** HexBinary list type */
+ public static final String STR_HEXBIN_LIST = "oor:hexBinary-list" ;
+
+ /** Symbolic int value for unknown type */
+ public static final int INT_UNKNOWN = -1 ;
+ /** Symbolic int value for string type */
+ public static final int INT_STRING = 0 ;
+ /** Symbolic int value for boolean type */
+ public static final int INT_BOOLEAN = 1 ;
+ /** Symbolic int value for short type */
+ public static final int INT_SHORT = 2 ;
+ /** Symbolic int value for int type */
+ public static final int INT_INT = 3 ;
+ /** Symbolic int value for long type */
+ public static final int INT_LONG = 4 ;
+ /** Symbolic int value for double type */
+ public static final int INT_DOUBLE = 5 ;
+ /** Symbolic int value for hexBinary type */
+ public static final int INT_HEXBIN = 6 ;
+ /** Symbolic int value for any type */
+ public static final int INT_ANY = 7 ;
+ /** Symbolic int value for string list type */
+ public static final int INT_STRING_LIST = 8 ;
+ /** Symbolic int value for boolean list type */
+ public static final int INT_BOOLEAN_LIST = 9 ;
+ /** Symbolic int value for short list type */
+ public static final int INT_SHORT_LIST = 10 ;
+ /** Symbolic int value for int list type */
+ public static final int INT_INT_LIST = 11 ;
+ /** Symbolic int value for long list type */
+ public static final int INT_LONG_LIST = 12 ;
+ /** Symbolic int value for double list type */
+ public static final int INT_DOUBLE_LIST = 13 ;
+ /** Symbolic int value for hexBinary list type */
+ public static final int INT_HEXBIN_LIST = 14 ;
+
+ /** The equivalent DataTypes */
+ public static final DataType UNKNOWN = new DataType(INT_UNKNOWN);
+ public static final DataType STRING = new DataType(INT_STRING);
+ public static final DataType BOOLEAN = new DataType(INT_BOOLEAN);
+ public static final DataType SHORT = new DataType(INT_SHORT);
+ public static final DataType INT = new DataType(INT_INT);
+ public static final DataType LONG = new DataType(INT_LONG);
+ public static final DataType DOUBLE = new DataType(INT_DOUBLE);
+ public static final DataType HEXBIN = new DataType(INT_HEXBIN);
+ public static final DataType ANY = new DataType(INT_ANY);
+ public static final DataType STRING_LIST = new DataType(INT_STRING_LIST);
+ public static final DataType BOOLEAN_LIST = new DataType(INT_BOOLEAN_LIST);
+ public static final DataType SHORT_LIST = new DataType(INT_SHORT_LIST);
+ public static final DataType INT_LIST = new DataType(INT_INT_LIST);
+ public static final DataType LONG_LIST = new DataType(INT_LONG_LIST);
+ public static final DataType DOUBLE_LIST = new DataType(INT_DOUBLE_LIST);
+ public static final DataType HEXBIN_LIST = new DataType(INT_HEXBIN_LIST);
+
+ /**
+ * Array aligned on int values of possible types
+ * to provide a string equivalent.
+ */
+ private static final String enumStrings [] = {
+ STR_STRING,
+ STR_BOOLEAN,
+ STR_SHORT,
+ STR_INT,
+ STR_LONG,
+ STR_DOUBLE,
+ STR_HEXBIN,
+ STR_ANY,
+ STR_STRING_LIST,
+ STR_BOOLEAN_LIST,
+ STR_SHORT_LIST,
+ STR_INT_LIST,
+ STR_LONG_LIST,
+ STR_DOUBLE_LIST,
+ STR_HEXBIN_LIST
+ } ;
+
+ private static final DataType enums[] = {
+ STRING,
+ BOOLEAN,
+ SHORT,
+ INT,
+ LONG,
+ DOUBLE,
+ HEXBIN,
+ ANY,
+ STRING_LIST,
+ BOOLEAN_LIST,
+ SHORT_LIST,
+ INT_LIST,
+ LONG_LIST,
+ DOUBLE_LIST,
+ HEXBIN_LIST
+ };
+
+ private DataType(int n) {
+ super(n);
+ }
+
+ protected String[] getEnumStrings() {
+ return enumStrings;
+ }
+ protected DataType[] getEnums() {
+ return enums;
+ }
+ /**
+ * Checks if the type is a list type.
+ *
+ * @return <code>true</code> if list type, otherwise
+ * <code>false</code>
+ */
+ public boolean isList() {
+ boolean success = false;
+ if (this != UNKNOWN) {
+ for (int i = 0; i < enums.length; i++) {
+ if (this == enums[i]) {
+ if (i >= FIRST_LIST_ELEMENT) {
+ success = true;
+ }
+ break;
+ }
+ }
+ }
+ return success;
+ }
+
+ /**
+ * Factory method for DataType instances where a
+ * string is the parameter.
+ *
+ * @param aString string name
+ * @return the corresponding <code>DataType</code>
+ */
+ public static DataType getDataType(String aString) {
+ for (int i=0; i < enumStrings.length; i++) {
+ if (aString.equals(enumStrings[i])){
+ return enums[i];
+ }
+ }
+ return DataType.UNKNOWN;
+ }
+
+ /**
+ * Factory method for DataType instances, where
+ * an int is the parameter.
+ *
+ * @param aIntValue int value
+ * @return the corresponding <code>DataType</code>
+ */
+ public static DataType getDataType(int aIntValue) {
+ if (aIntValue >=0 && aIntValue < enums.length) {
+ return enums[aIntValue];
+ }
+ return DataType.UNKNOWN;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/ElementCopyException.java b/src/com/sun/apoc/spi/cfgtree/ElementCopyException.java
new file mode 100644
index 0000000..55b40ef
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/ElementCopyException.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree;
+
+public class ElementCopyException extends PolicyTreeException {
+
+ private static final String COPY_POLICYTREE_KEY =
+ "error.spi.policytree.element.copy";
+
+ protected String mElementName;
+ protected String mElementType = null;
+
+ public ElementCopyException () {
+ super();
+ }
+
+ public ElementCopyException (String elementType, String elementName,
+ Throwable cause) {
+ super(cause);
+ mElementName = elementName;
+ mElementType = elementType;
+ mMessageKey = COPY_POLICYTREE_KEY;
+ mMessageParams = new Object[]{mElementType, mElementName};
+ }
+
+ public String getElementName() { return mElementName; }
+ public String getElementType() { return mElementType; }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/InvalidDataTypeException.java b/src/com/sun/apoc/spi/cfgtree/InvalidDataTypeException.java
new file mode 100644
index 0000000..addc3f0
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/InvalidDataTypeException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree;
+
+public class InvalidDataTypeException extends PolicyTreeException {
+
+ private static final String INVALID_DATA_POLICYTREE_KEY =
+ "error.spi.policytree.datatype.invalid";
+
+ protected String mDataType = null;
+
+ public InvalidDataTypeException () {
+ super();
+ }
+
+ public InvalidDataTypeException (String datatype) {
+ super();
+ mDataType = datatype;
+ mMessageKey = INVALID_DATA_POLICYTREE_KEY;
+ mMessageParams = new Object[]{mDataType};
+ }
+
+ public InvalidDataTypeException (String datatype, Throwable cause) {
+ super(cause);
+ mDataType = datatype;
+ mMessageKey = INVALID_DATA_POLICYTREE_KEY;
+ mMessageParams = new Object[]{mDataType};
+ }
+
+ public String getDataType() { return mDataType; }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/MandatoryElementException.java b/src/com/sun/apoc/spi/cfgtree/MandatoryElementException.java
new file mode 100644
index 0000000..1166536
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/MandatoryElementException.java
@@ -0,0 +1,72 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree;
+
+public class MandatoryElementException extends PolicyTreeException {
+
+ private static final String MANDATORY_POLICYTREE_KEY =
+ "error.spi.policytree.element.mandatory";
+ public static final String REMOVE_MANDATORY_KEY =
+ "error.spi.policytree.element.mandatory.noremove";
+
+ protected String mElementName = null;
+ protected String mElementType = null;
+
+ public MandatoryElementException () {
+ super();
+ }
+
+ public MandatoryElementException (String elementType,
+ String elementName) {
+ super();
+ mElementName = elementName;
+ mElementType = elementType;
+ mMessageKey = MANDATORY_POLICYTREE_KEY;
+ mMessageParams = new Object[]{mElementType, mElementName};
+ }
+
+ public MandatoryElementException (String elementType,
+ String elementName,
+ String messageKey) {
+ super();
+ mElementName = elementName;
+ mElementType = elementType;
+ mMessageKey = messageKey;
+ mMessageParams = new Object[]{mElementType, mElementName};
+ }
+
+ public String getElementName() { return mElementName; }
+ public String getElementType() { return mElementType; }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/NodeKey.java b/src/com/sun/apoc/spi/cfgtree/NodeKey.java
new file mode 100644
index 0000000..41a1419
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/NodeKey.java
@@ -0,0 +1,52 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Encapsulates information needed for accessing configuration data.
+ *
+ */
+public class NodeKey
+{
+ /** policy id */
+ public String mPolicyId = null ;
+ /** locale(s) to be used */
+ public String mLocale = null;
+ /** Policy where data located */
+ public Policy mLayer = null;
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/NodeParsing.java b/src/com/sun/apoc/spi/cfgtree/NodeParsing.java
new file mode 100644
index 0000000..c4b550f
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/NodeParsing.java
@@ -0,0 +1,476 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import java.util.Stack;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNodeImpl;
+import com.sun.apoc.spi.cfgtree.policynode.ReadWritePolicyNodeImpl;
+import com.sun.apoc.spi.cfgtree.property.PropertyImpl;
+import com.sun.apoc.spi.cfgtree.property.ReadWritePropertyImpl;
+import com.sun.apoc.spi.cfgtree.readwrite.ReadWritePolicyTreeImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Used to provide constants and utilities related to the
+ * parsing of the schema and the output of nodes.
+ *
+ */
+public class NodeParsing extends DefaultHandler
+{
+ /** Namespace for the OOR attributes */
+ public static final String OOR_NAMESPACE = "oor:" ;
+ /** Namespace for the XML attributes */
+ public static final String XML_NAMESPACE = "xml:" ;
+ /** Namespace for the XSI attributes */
+ public static final String XSI_NAMESPACE = "xsi:" ;
+ /** XML Namespace */
+ public static final String XMLNS_NAMESPACE = "xmlns:" ;
+ /** xmlns:oor attribute used in component schema,
+ * as in xmlns:oor="http://openoffice.org.policy" */
+ public static final String XMLNSOOR_ATTR = XMLNS_NAMESPACE + "oor" ;
+ /** xmlns:xs attribute used in component schema,
+ * as in xmlns:xs="http://www.w3.org/2001/XMLSchema" */
+ public static final String XMLNSXS_ATTR = XMLNS_NAMESPACE + "xs" ;
+ /** xmlns:xsi attribute used in component schema,
+ * as in xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" */
+ public static final String XMLNSXSI_ATTR = XMLNS_NAMESPACE + "xsi" ;
+ /** Name attribute,
+ * as in &lt;group <b>oor:name</b>="groupName"/&gt; */
+ public static final String NAME_ATTR = OOR_NAMESPACE + "name" ;
+ /** Value type attribute,
+ * as in &lt;prop <b>oor:type</b>="xs:string"/&gt; */
+ public static final String TYPE_ATTR = OOR_NAMESPACE + "type" ;
+ /** Locale attribute,
+ * as in &lt;value <b>xml:lang</b>="en-US"/&gt; */
+ public static final String LOCALE_ATTR = XML_NAMESPACE + "lang" ;
+ /** Separator attribute,
+ * as in &lt;value <b>oor:separator</b>=" "/&gt; */
+ public static final String SEPARATOR_ATTR = OOR_NAMESPACE + "separator" ;
+ /** Localized attribute,
+ * as in &lt;prop <b>oor:localized</b>="true"/&gt; */
+ public static final String LOCALIZED_ATTR = OOR_NAMESPACE + "localized" ;
+ /** Component attribute,
+ * as in &lt;import <b>oor:component</b>="someComponent"/&gt; */
+ public static final String COMPONENT_ATTR = OOR_NAMESPACE + "component" ;
+ /** Package attribute,
+ * as in &lt;component-schema <b>oor:package</b>="somePackage"/&gt; */
+ public static final String PACKAGE_ATTR = OOR_NAMESPACE + "package" ;
+ /** Node-type (set template) attribute,
+ * as in &lt;set <b>oor:node-type</b>="templateName"/&gt; */
+ public static final String NODETYPE_ATTR = OOR_NAMESPACE + "node-type" ;
+ /** Context attribute,
+ * as in &lt;group <b>oor:context</b>="somePackage/someSubNode"/&gt; */
+ public static final String CONTEXT_ATTR = OOR_NAMESPACE + "context" ;
+ /** Operation attribute,
+ * as in &lt;group <b>oor:op</b>="remove"/&gt; */
+ public static final String OPERATION_ATTR = OOR_NAMESPACE + "op" ;
+ /** Nillable attribute,
+ * as in &lt;prop <b>oor:nillable</b>="true"/&gt; */
+ public static final String NILLABLE_ATTR = OOR_NAMESPACE + "nillable" ;
+ /** Finalized attribute,
+ * as in &lt;prop <b>oor:finalized</b>="true"/&gt; */
+ public static final String FINALIZED_ATTR = OOR_NAMESPACE + "finalized" ;
+ /** Read-only attribute,
+ * as in &lt;prop <b>oor:readonly</b>="true"/&gt; */
+ public static final String READONLY_ATTR = OOR_NAMESPACE + "readonly" ;
+ /** Mandatory attribute,
+ * as in &lt;group <b>oor:mandatory</b>="true"/&gt; */
+ public static final String MANDATORY_ATTR = OOR_NAMESPACE + "mandatory" ;
+ /** Value attribute,
+ * as in &lt;group <b>oor:value</b>="someValue"/&gt; */
+ public static final String VALUE_ATTR = OOR_NAMESPACE + "value" ;
+ /** Nil attribute (for value node),
+ * as in &lt;prop <b>xsi:nil</b>="true"/&gt; */
+ public static final String NIL_ATTR = XSI_NAMESPACE + "nil" ;
+ /** whitespace */
+ public static final String WHITESPACE = " ";
+ public static final String NODE_TAG = "node";
+ public static final String PROP_TAG = "prop";
+ public static final String VALUE_TAG = "value";
+ public static final String COMPONENT_DATA_TAG = "component-data" ;
+
+ /** used when creating a NodeValueImpl to indicate which layer was
+ the source of this value */
+ private Policy mSourceLayer;
+ /** id of policy being read */
+ private String mPolicyId;
+ /** indicates what locale is required (as specified by java proxy).
+ Needed for PropertyImpl to return correct NodeValueImpl(s) for
+ specified locale(s) */
+ private String mLocale ;
+ /** Locator object used for traces */
+ private Locator mLocator ;
+ /** Stack containing the parsing context, i.e the elements
+ * encountered during parsing */
+ private Stack mContextStack = new Stack() ;
+ /** Root object of the tree parsed */
+ private Object mRoot ;
+ /** reference to the PolicyTree instance */
+ private PolicyTreeImpl mPolicyTree;
+ /** AttributesImpl object for reuse */
+ private static Attributes mNodeParsingAttributes = new AttributesImpl();
+ /** StringBuffer used for creating concatanated strings */
+ private StringBuffer tmpBuf =
+ new StringBuffer(PolicyTree.BUFFER_SIZE);
+
+ private static class ParseInfo
+ {
+ Object mObject = null ;
+ Attributes mAttributes = null ;
+
+ ParseInfo(Object aObject,
+ Attributes aAttributes) {
+ mObject = aObject ;
+ if (aAttributes != null) {
+ ((AttributesImpl)mNodeParsingAttributes).clear();
+ mAttributes = mNodeParsingAttributes ;
+ ((AttributesImpl)mAttributes).setAttributes(aAttributes) ;
+ }
+ }
+ } ;
+ /**
+ * Returns the root object.
+ *
+ * @return the root object
+ */
+ public Object getRoot() { return mRoot; }
+
+ /**
+ * Sets the value of the layer that is the source of
+ * this data.
+ *
+ * @param aLayer name of the layer that is the source of
+ * this data
+ */
+ public void setSourceLayer(Policy aLayer) {
+ mSourceLayer = aLayer;
+ }
+
+ /**
+ * Sets the id of the policy being read.
+ *
+ * @param aPolicyId id of the policy
+ */
+ public void setPolicyId(String aPolicyId) {
+ mPolicyId = aPolicyId;
+ }
+
+ /**
+ * Sets the reference to the <code>PolicyTreeImpl</code> instance.
+ *
+ * @param aPolicyTree reference to PolicyTree instance
+ */
+ public void setPolicyTree(PolicyTreeImpl aPolicyTree) {
+ mPolicyTree = aPolicyTree;
+ }
+
+ /**
+ * Sets the value for the locale.
+ *
+ * @param aLocale specified locale
+ */
+ public void setLocale(String aLocale) { mLocale = aLocale; }
+
+ /**
+ * Returns the value for the locale.
+ *
+ * @return specified locale
+ */
+ protected String getLocale() { return mLocale; }
+
+ /**
+ * Sets the Locator to be used during the parsing.
+ *
+ * @param aLocator locator object
+ */
+ public void setDocumentLocator(Locator aLocator) {
+ mLocator = aLocator ;
+ }
+
+ /**
+ * If the mandatory attribute is set then sets that boolean
+ * member of the node, and sets the profile where
+ * this attribute originated.
+ *
+ * @param aNode container of the mandatory property
+ * @param aValue string value of the mandatory property
+ */
+ private void setParsedMandatory(PolicyNodeImpl aNode, String aValue) {
+ boolean mandatory = (Boolean.valueOf(aValue)).booleanValue();
+ if (mandatory) {
+ aNode.setMandatoryFlag();
+ aNode.setOriginOfMandatory(mSourceLayer);
+ }
+ }
+
+ /**
+ * If the mandatory attribute is set then sets that boolean
+ * member of the property, and sets the profile
+ * where this attribute originated.
+ *
+ * @param aNode container of the mandatory property
+ * @param aValue string value of the mandatory property
+ */
+ private void setParsedMandatory(PropertyImpl aProperty, String aValue) {
+ boolean mandatory = (Boolean.valueOf(aValue)).booleanValue();
+ if (mandatory) {
+ aProperty.setMandatoryFlag();
+ aProperty.setOriginOfMandatory(mSourceLayer);
+ }
+ }
+
+ /**
+ * Fills the properties of an element with the contents
+ * of the XML attributes.
+ *
+ * @param aElement element to fill
+ * @param aAttributes attributes of the XML element
+ */
+ private void handleProperties(ConfigElementImpl aElement,
+ Attributes aAttributes) {
+ String attrValue = null;
+ attrValue = aAttributes.getValue(OPERATION_ATTR);
+ if (attrValue != null) {
+ aElement.setOperationType(OperationType.getInt(attrValue));
+ }
+ attrValue = aAttributes.getValue(MANDATORY_ATTR);
+ if (attrValue != null) {
+ setParsedMandatory((PolicyNodeImpl)aElement, attrValue);
+ }
+ attrValue = aAttributes.getValue(PACKAGE_ATTR);
+ if (attrValue != null) {
+ aElement.setPackage(attrValue);
+ }
+ attrValue = aAttributes.getValue(TYPE_ATTR);
+ if (attrValue != null) {
+ ((PropertyImpl)aElement).setDataType(DataType.getDataType(attrValue));
+ }
+ attrValue = aAttributes.getValue(NILLABLE_ATTR);
+ if (attrValue != null) {
+ ((PropertyImpl)aElement).setNillable((Boolean.valueOf(attrValue)).booleanValue());
+ }
+ }
+
+ /**
+ * Builds an element corresponding to the description of an
+ * element.
+ *
+ * @param aNamespace namespace URI
+ * @param aLocalName local name
+ * @param aFullName full name with prefix
+ * @param aAttributes element attributes
+ * @return ParseInfo describing the node
+ */
+ private ParseInfo createElement(String aNamespace, String aLocalName,
+ String aFullName,
+ Attributes aAttributes) {
+ if (mPolicyTree instanceof ReadWritePolicyTreeImpl) {
+ return createReadWriteElement(aNamespace, aLocalName,
+ aFullName, aAttributes);
+ } else {
+ return createReadWriteElement(aNamespace, aLocalName,
+ aFullName, aAttributes);
+ }
+ }
+
+ /**
+ * Builds a readwrite element corresponding to the description of
+ * the element.
+ *
+ * @param aNamespace namespace URI
+ * @param aLocalName local name
+ * @param aFullName full name with prefix
+ * @param aAttributes element attributes
+ * @return ParseInfo describing the node
+ */
+ private ParseInfo createReadWriteElement(String aNamespace,
+ String aLocalName, String aFullName, Attributes aAttributes) {
+ ConfigElementImpl node = null ;
+ if (aLocalName.equals(NODE_TAG) ||
+ aLocalName.equals(COMPONENT_DATA_TAG)) {
+ node = new ReadWritePolicyNodeImpl();
+ ((PolicyNodeImpl)node).setOrigin(mSourceLayer);
+ String attrValue = aAttributes.getValue(FINALIZED_ATTR);
+ if (attrValue != null) {
+ ((PolicyNodeImpl)node).setFinalized(
+ (Boolean.valueOf(attrValue)).booleanValue(),
+ null, mSourceLayer);
+ }
+ } else if (aLocalName.equals(PROP_TAG)) {
+ node = new ReadWritePropertyImpl();
+ ((PropertyImpl)node).setRequiredLocale(mLocale);
+ ((PropertyImpl)node).setOrigin(mSourceLayer);
+ String attrValue = aAttributes.getValue(FINALIZED_ATTR);
+ if (attrValue != null) {
+ ((PropertyImpl)node).setFinalized(
+ (Boolean.valueOf(attrValue)).booleanValue(),
+ null, mSourceLayer);
+ }
+ }
+ if (node == null) { return null; }
+ node.setPolicyTree(mPolicyTree);
+ if (node.getName() == null) {
+ node.setName(aAttributes.getValue(NAME_ATTR)) ;
+ }
+ if (!mContextStack.empty()) {
+ ParseInfo parent = (ParseInfo) mContextStack.peek() ;
+ if (parent != null) {
+ if (node instanceof PolicyNodeImpl) {
+ ((ReadWritePolicyNodeImpl) parent.mObject).addChildNode((PolicyNodeImpl)node) ;
+ } else {
+ ((ReadWritePolicyNodeImpl) parent.mObject).addProperty((PropertyImpl)node) ;
+ }
+
+ }
+ }
+ handleProperties(node, aAttributes) ;
+ return new ParseInfo(node, aAttributes) ;
+ }
+
+ /**
+ * Creates a NodeValueImpl object from the attributes of an element.
+ *
+ * @param aAttributes element's attributes
+ * @return <code>ParseInfo</code> describing the value object
+ */
+ private ParseInfo createValue(Attributes aAttributes) {
+ if (mContextStack.empty()) { return null ; }
+ NodeValueImpl value = new NodeValueImpl() ;
+ ParseInfo parent = (ParseInfo) mContextStack.peek() ;
+ Attributes parentAttr = parent.mAttributes ;
+ int length = parentAttr.getLength();
+ /* check if xsi:nil attribute is set */
+ String nilValue = aAttributes.getValue(NIL_ATTR);
+ if (nilValue != null && nilValue.equals("true")) {
+ value.setNilAttribute(true);
+ }
+ String localeName = (String)aAttributes.getValue(LOCALE_ATTR) ;
+ if (localeName != null) {
+ value.setLocaleName(localeName) ;
+ }
+ String typeAttr = (String)parentAttr.getValue(TYPE_ATTR);
+ DataType dataType = DataType.UNKNOWN;
+ if (typeAttr != null) {
+ dataType = DataType.getDataType(typeAttr);
+ value.setDataType(dataType);
+ }
+ String separator = aAttributes.getValue(SEPARATOR_ATTR);
+ if (separator != null) {
+ ((PropertyImpl) parent.mObject).setSeparator(separator);
+ } else {
+ /* if this is a list, and separator is not
+ specified, then the default separator
+ is a whitespace */
+ if (dataType.getIntValue() >=
+ DataType.FIRST_LIST_ELEMENT) {
+ ((PropertyImpl) parent.mObject).setSeparator(WHITESPACE);
+ }
+ }
+ try {
+ ((PropertyImpl) parent.mObject).setParsedValue(
+ value, localeName) ;
+ } catch (Exception ignoreException) { }
+ value.setOrigin(mSourceLayer);
+ return new ParseInfo(value, aAttributes) ;
+ }
+
+
+ /**
+ * Handles the beginning of an element.
+ * Creates a new node and pushes it on the context stack.
+ *
+ * @param aNamespace namespace URI
+ * @param aLocalName local name
+ * @param aFullName full name with prefix
+ * @param aAttributes attributes of the element
+ */
+ public void startElement(String aNamespace, String aLocalName,
+ String aFullName, Attributes aAttributes) {
+ ParseInfo stackedObject = null ;
+ if (aLocalName.equals(VALUE_TAG)) {
+ stackedObject = createValue(aAttributes) ;
+ } else {
+ // Otherwise create a node.
+ stackedObject = createElement(aNamespace, aLocalName,
+ aFullName, aAttributes) ;
+ }
+ /* Anyway, always put something on the stack so that the
+ endElement doesn't have to check for the special cases. */
+ mContextStack.push(stackedObject) ;
+ }
+
+ /**
+ * Handles the end of an element.
+ * Gets one step up in the context stack.
+ *
+ * @param aNamespace namespace URI
+ * @param aLocalName element name
+ * @param aFullName full name including prefix
+ */
+ public void endElement(String aNamespace, String aLocalName,
+ String aFullName) {
+ Object stackObj = mContextStack.pop() ;
+ if (stackObj != null) {
+ mRoot = ((ParseInfo) stackObj).mObject ;
+ }
+ }
+
+ /**
+ * Handles a character string (text data).
+ * Fills the appropriate NodeValueImpl object.
+ *
+ * @param aCharacters character array
+ * @param aStart beginning of the data
+ * @param aLength length of the data
+ */
+ public void characters(char aCharacters [], int aStart, int aLength) {
+ String value = new String(aCharacters, aStart, aLength) ;
+ //System.out.println("Characters:" + value) ;
+ if (mContextStack.empty()) { return; }
+ ParseInfo parent = (ParseInfo) mContextStack.peek() ;
+ if (parent == null) { return; }
+ if(parent.mObject != null &&
+ parent.mObject instanceof com.sun.apoc.spi.cfgtree.NodeValueImpl) {
+ ((NodeValueImpl) parent.mObject).appendContents(value) ;
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/NodeValueImpl.java b/src/com/sun/apoc/spi/cfgtree/NodeValueImpl.java
new file mode 100644
index 0000000..cc4535a
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/NodeValueImpl.java
@@ -0,0 +1,557 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Vector;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.property.InvalidPropertyException;
+import com.sun.apoc.spi.cfgtree.property.PropertyImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Handles storage of the value of a node.
+ *
+ */
+public class NodeValueImpl
+{
+ /** buffer for storing value */
+ private StringBuffer mValueBuf;
+ /** Value array */
+ public String mValueArray [] ;
+ /** Value type */
+ private DataType mDataType = DataType.UNKNOWN ;
+ /** Name of the locale for the value */
+ private String mLocaleName ;
+ /** layer where this value originated */
+ private Policy mOriginLayer ;
+ /** nil attribute */
+ private boolean mNilAttribute = false;
+ /** flag indicating contents have been set originally */
+ private boolean mIsContentsSet = false;
+ /** flag indicating if this NodeValueImpl was modified at
+ the entity contained update layer */
+ private boolean mIsModifiedAtTopLayer = false;
+ /** property node for this value */
+ private PropertyImpl mPropertyImpl;
+ /** module name used by exceptions */
+ private static final String MODULE = "NodeValueImpl";
+
+ /**
+ * Returns a string representing the contents of the value.
+ *
+ * @return contents of the value as a string
+ */
+ public String getContents() {
+ if (!mIsContentsSet) {
+ if (mValueBuf != null) {
+ setOriginalContents(mValueBuf.toString());
+ }
+ mIsContentsSet = true;
+ }
+ if ((mValueArray == null) || (mValueArray.length < 1)) {
+ return null;
+ }
+ String retCode = mValueArray[0];
+ if (getSeparator() == null) { return retCode ; }
+ for (int i = 1; i < mValueArray.length; ++ i) {
+ retCode += getSeparator() + mValueArray[i];
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the array representing the contents.
+ *
+ * @return an array representing contents
+ */
+ public String[] getValueArray() {
+ if (!mIsContentsSet) {
+ if (mValueBuf != null) {
+ setOriginalContents(mValueBuf.toString());
+ }
+ mIsContentsSet = true;
+ }
+ if (mValueArray == null) {
+ return new String[0];
+ }
+ return mValueArray;
+ }
+
+ /**
+ * Sets a new value for the contents.
+ *
+ * @param aContents the data
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void setNewContents(String aContents) throws SPIException {
+ /* throw an exception if the node is readonly */
+ mPropertyImpl.checkIfReadOnly();
+ String origContents = getContents();
+ String[] origValues = null;
+ /* if new contents are different to the original
+ contents then check and set the new contents */
+ if ((origContents != null) && !origContents.equals(aContents)) {
+ if (mValueArray != null) {
+ origValues = new String[mValueArray.length];
+ for (int i = 0 ; i < mValueArray.length; i++) {
+ origValues[i] = new String(mValueArray[i]);
+ }
+ }
+ }
+ setOriginalContents(aContents);
+ /* check that the new contents comply with
+ the value type specified by the property node */
+ try {
+ checkContentsAgainstDataType(mDataType);
+ } catch (SPIException e) {
+ mValueArray = origValues;
+ throw e;
+ }
+ /* set the hasNilAttribute to false */
+ mNilAttribute = false;
+ /* indicate that this value was changed at
+ uppermost layer */
+ mIsModifiedAtTopLayer = true;
+ /* set the origin for this nodevalue */
+ mOriginLayer = mPropertyImpl.getPolicyTree().getPolicy();
+ /* ensure the nodevalue is stored in the propertynode
+ (this is necessary because of the provision of
+ fallback values in PropertyImpl.getValue()) */
+ mPropertyImpl.setNodeValue(this, mPropertyImpl.getRequiredLocale());
+ /* if the property was not introduced on this layer, then
+ ensure the opertation attribute is "op=modify" */
+ if (!mPropertyImpl.isAddedAtTopLayer()) {
+ mPropertyImpl.setOperationType(OperationType.OP_MODIFY);
+ }
+ }
+
+ /**
+ * Sets the value to nil.
+ *
+ * @throws SPIException if error occurs
+ * @throws InvalidPropertyException if property
+ * cannot be set to nil
+ */
+ public void setValueToNil() throws SPIException {
+ /* throw an exception if the node is readonly */
+ mPropertyImpl.checkIfReadOnly();
+ /* throw an exception if the node is not nillable */
+ if (!mPropertyImpl.isNillable()) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.NOTNIL_PROPERTY_KEY,
+ mPropertyImpl.getName());
+ }
+ /* ensure contents were originally set */
+ if (!mIsContentsSet) {
+ getContents();
+ }
+ /* set contents to null */
+ mValueArray = null;
+ mNilAttribute = true;
+ mIsModifiedAtTopLayer = true;
+ /* set the origin for this nodevalue */
+ mOriginLayer = mPropertyImpl.getPolicyTree().getPolicy();
+ /* ensure the nodevalue is stored in the propertynode
+ (this is necessary because of the provision of
+ fallback values in PropertyImpl.getValue()) */
+ mPropertyImpl.setNodeValue(this, mPropertyImpl.getRequiredLocale());
+ /* if the property was not introduced on this layer, then
+ ensure the opertation attribute is "op=modify" */
+ if (!mPropertyImpl.isAddedAtTopLayer()) {
+ mPropertyImpl.setOperationType(OperationType.OP_MODIFY);
+ }
+ }
+
+ /**
+ * Returns the layer where this value was set.
+ *
+ * @return layer that is the source of this value
+ */
+ public Policy getOrigin() {
+ return mOriginLayer;
+ }
+
+ /**
+ * Checks if the xsi:nil attribute has been set.
+ *
+ * @return <code>true</code> if this attribute has been
+ * set, otherwise <code>false</code>a
+ */
+ public boolean hasNilAttribute () { return mNilAttribute; }
+
+ /**
+ * Returns the type of the value.
+ *
+ * @return value type
+ */
+ public DataType getDataType() { return mDataType ; }
+
+ /**
+ * Outputs the contents of the value to an XML PrintStream.
+ *
+ * @param aIndent indent prefix for the print out
+ * @param aOutput PrintStream to write to
+ */
+ public void printToStream(String aIndent, PrintStream aOutput) {
+ aOutput.print(aIndent + "<" + NodeParsing.VALUE_TAG) ;
+ if (mLocaleName != null) {
+ aOutput.print(" " + NodeParsing.LOCALE_ATTR + "=\"") ;
+ aOutput.print(mLocaleName + "\"") ;
+ }
+ if (getSeparator() != null && !getSeparator().equals(NodeParsing.WHITESPACE)) {
+ aOutput.print(" " + NodeParsing.SEPARATOR_ATTR + "=\"") ;
+ aOutput.print(getSeparator() + "\"") ;
+ }
+ printXMLValues(aOutput) ;
+ }
+
+ /**
+ * Prints a string as a UTF8 byte array into a print stream
+ * and performs encoding into entities of the special XML
+ * characters.
+ *
+ * @param aStream stream to write to
+ * @param aString string to normalise
+ */
+ private void printXMLString(PrintStream aStream, String aString) {
+ byte [] encodedString ;
+
+ try {
+ encodedString = aString.getBytes("UTF8") ;
+ }
+ catch (UnsupportedEncodingException exception) {
+ // Not good, but UTF8 is supposed to be part
+ // of the list of supported encodings by every
+ // Java implementation...
+ aStream.print(aString) ;
+ return ;
+ }
+ for (int i = 0 ; i < encodedString.length ; ++ i) {
+ byte character = encodedString [i] ;
+
+ switch (character) {
+ case '&': aStream.print("&amp;") ; break ;
+ case '<': aStream.print("&lt;") ; break ;
+ case '>': aStream.print("&gt;") ; break ;
+ default: aStream.write(character) ; break ;
+ }
+ }
+ }
+
+ /**
+ * Prints in an print stream the values as an UTF8 encoded
+ * string, suitable for XML dumping.
+ *
+ * @param aStream print stream
+ */
+ private void printXMLValues(PrintStream aStream) {
+ if (!mIsContentsSet) {
+ if (mValueBuf != null) {
+ setOriginalContents(mValueBuf.toString());
+ }
+ else { mIsContentsSet = true; }
+ }
+ if (mValueArray != null ) {
+ aStream.print(">");
+ int length = mValueArray.length;
+ if (length > 0) {
+ printXMLString(aStream, mValueArray [0]);
+ }
+ if (getSeparator() != null && length > 1) {
+ for (int i = 1 ; i < mValueArray.length ; ++ i) {
+ printXMLString(aStream, getSeparator());
+ printXMLString(aStream, mValueArray [i]);
+ }
+ }
+ aStream.print("</"+NodeParsing.VALUE_TAG+">\n");
+ }
+ else if (mNilAttribute) {
+ aStream.print(" "+NodeParsing.NIL_ATTR+"=\"true\""+"/>\n");
+ }
+ else {
+ aStream.print("/>\n");
+ }
+ }
+
+ /**
+ * Create a copy of a <code>NodeValueImpl</code>.
+ *
+ * @return a copy of the <code>NodeValueImpl</code>
+ */
+ public NodeValueImpl copyNodeValueImpl() {
+ NodeValueImpl retValue = new NodeValueImpl();
+ /* ensure that mValueBuf in original has been read */
+ if (!mIsContentsSet) {
+ getContents();
+ }
+ retValue.mIsContentsSet = true;
+ if (mValueArray != null) {
+ String[] copiedValues = new String[mValueArray.length];
+ for (int i = 0; i < mValueArray.length; i++) {
+ copiedValues[i] = new String(mValueArray[i]);
+ }
+ retValue.mValueArray = copiedValues;
+ }
+ retValue.mDataType = mDataType;
+ retValue.mLocaleName = mLocaleName;
+ retValue.mNilAttribute = mNilAttribute;
+ retValue.mPropertyImpl = mPropertyImpl;
+ retValue.mOriginLayer = mOriginLayer;
+ retValue.mIsModifiedAtTopLayer = mIsModifiedAtTopLayer;
+ return retValue;
+ }
+
+ /**
+ * Checks if a value complies with the type specified by
+ * the property node. Check is only done for values of type
+ * short, int, long, double, boolean, or the corresponding
+ * lists.
+ *
+ * @param aDataType numerical representation of the value
+ * type specified by the property node
+ * @throws InvalidDataTypeException if aDataType does not comply
+ */
+ public void checkContentsAgainstDataType(DataType aDataType)
+ throws SPIException {
+ if (mValueArray == null || mValueArray.length < 1) { return; }
+ int valueType = aDataType.getIntValue();
+ /* if the value type is unknown then return */
+ if (valueType == DataType.INT_UNKNOWN) { return; }
+ if (valueType == DataType.INT_SHORT ||
+ valueType == DataType.INT_INT ||
+ valueType == DataType.INT_LONG) {
+ long value = 0;
+ switch(valueType) {
+ case DataType.INT_SHORT:
+ for (int i = 0; i < mValueArray.length; i++) {
+ try {
+ value = Short.parseShort(mValueArray[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidDataTypeException(
+ aDataType.getStringValue(), nfe);
+ }
+ }
+ break;
+ case DataType.INT_INT:
+ for (int i = 0; i < mValueArray.length; i++) {
+ try {
+ value = Integer.parseInt(mValueArray[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidDataTypeException(
+ aDataType.getStringValue(), nfe);
+ }
+ }
+ break;
+ case DataType.INT_LONG:
+ for (int i = 0; i < mValueArray.length; i++) {
+ try {
+ value = Long.parseLong(mValueArray[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidDataTypeException(
+ aDataType.getStringValue(), nfe);
+ }
+ }
+ break;
+ };
+ } else if (valueType == DataType.INT_DOUBLE) {
+ for (int i = 0; i < mValueArray.length; i++) {
+ try {
+ double doubleValue = Double.parseDouble(mValueArray[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidDataTypeException(
+ aDataType.getStringValue(), nfe);
+ }
+ }
+ } else if (valueType == DataType.INT_BOOLEAN) {
+ for (int i = 0; i < mValueArray.length; i++) {
+ if (mValueArray[i].length() == 1) {
+ /* the value should be 1 or zero */
+ if(!(mValueArray[i].equals("1") ||
+ mValueArray[i].equals("0"))) {
+ throw new InvalidDataTypeException(
+ aDataType.getStringValue());
+ }
+ } else {
+ String booleanStr = mValueArray[i].toLowerCase();
+ if (!(booleanStr.equals("true") ||
+ booleanStr.equals("false"))) {
+ throw new InvalidDataTypeException(
+ aDataType.getStringValue());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the value of the nil attribute.
+ *
+ * @param <code>true</code> or </code>false</code>
+ */
+ public void setNilAttribute(boolean aNilAttribute) {
+ mNilAttribute = aNilAttribute;
+ }
+
+ /**
+ * Sets a pointer to the property node to which this
+ * value belongs.
+ *
+ * @param aNode the property node
+ */
+ public void setPropertyImpl(PropertyImpl aNode) {
+ mPropertyImpl = aNode;
+ }
+
+ /**
+ * Sets a flag indicating the <code>NodeValueImpl</code> was modified
+ * at the final layer.
+ */
+ public void setModifiedAtTopLayer() {
+ mIsModifiedAtTopLayer = true;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not the
+ * <code>NodeValueImpl</code> was modified at the final layer.
+ *
+ * @return <code>true</code> if was modified at
+ * final layer, otherwise <code>false</code>
+ */
+ public boolean isModifiedAtTopLayer() { return mIsModifiedAtTopLayer; }
+
+ /**
+ * Sets the type of the value from the int representation.
+ *
+ * @param aDataType symbolic int value for the type
+ */
+ public void setDataType(DataType aDataType) {
+ mDataType = aDataType ;
+ }
+
+ /**
+ * Sets the locale name of the value.
+ *
+ * @param aLocaleName name of the locale
+ */
+ public void setLocaleName(String aLocaleName) {
+ mLocaleName = aLocaleName ;
+ }
+
+ /**
+ * Returns the name of the locale for the value.
+ *
+ * @return name of the locale
+ */
+ public String getLocaleName() { return mLocaleName ; }
+
+ /**
+ * Returns the separator used when producing the values as
+ * one string.
+ *
+ * @return separator character
+ */
+ public String getSeparator() { return mPropertyImpl.getSeparator() ; }
+
+ /*
+ * Used by parser to set the original contents
+ * during parsing of the configuration data.
+ * No checking is done, and no exception is thrown.
+ *
+ * @param aContents the data
+ */
+ public void setOriginalContents(String aContents) {
+ String valueStr = aContents;
+ if (getSeparator() == null) {
+ mValueArray = new String[1];
+ mValueArray[0] = valueStr;
+ }
+ else if (getSeparator() == NodeParsing.WHITESPACE) {
+ mValueArray = valueStr.split(getSeparator());
+ }
+ else {
+ int start = 0;
+ int end = 0;
+ Vector results = new Vector();
+ while (start <= valueStr.length()) {
+ end = valueStr.indexOf(getSeparator());
+ if (end < 0 ) {
+ /* just one item in list */
+ results.add(valueStr);
+ break;
+ }
+ String resultStr = valueStr.substring(start, end);
+ resultStr.trim();
+ results.add(resultStr);
+ valueStr = valueStr.substring(end + 1, valueStr.length());
+ }
+ if (results != null && !results.isEmpty()) {
+ int size = results.size();
+ mValueArray = new String[size];
+ for (int i = 0; i < size; i++) {
+ mValueArray[i] = new String((String)results.get(i));
+ }
+ }
+ }
+ mIsContentsSet = true;
+ /* set the hasNilAttribute to false */
+ mNilAttribute = false;
+ }
+
+ /**
+ * Appends a string read during parsing a value to a buffer.
+ *
+ * @param aData the data read
+ */
+ public void appendContents(String aContent) {
+ if (mValueBuf == null) {
+ mValueBuf = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ }
+ mValueBuf.append(aContent);
+ }
+
+ /**
+ * Sets the layer that is the source of this value.
+ *
+ * @param aLayer layer that is the source of this value
+ */
+ public void setOrigin(Policy aLayer) {
+ mOriginLayer = aLayer;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/OperationType.java b/src/com/sun/apoc/spi/cfgtree/OperationType.java
new file mode 100644
index 0000000..d620799
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/OperationType.java
@@ -0,0 +1,104 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+
+/**
+ * Handles the possible types of the operation values and
+ * their storage as integers.
+ *
+ */
+public class OperationType
+{
+ /** modify operation string */
+ public static final String MODIFY_STR = "modify" ;
+ /** replace operation string */
+ public static final String REPLACE_STR = "replace" ;
+ /** remove operation string */
+ public static final String REMOVE_STR = "remove" ;
+ /** reset operation string */
+ public static final String RESET_STR = "reset" ;
+
+ /** symbolic int for invalid operation */
+ public static final int OP_UNKNOWN = -1;
+ /** symbolic int for modify operation */
+ public static final int OP_MODIFY = 0;
+ /** symbolic int for replace operation */
+ public static final int OP_REPLACE = 1;
+ /** symbolic int for remove operation */
+ public static final int OP_REMOVE = 2;
+ /** symbolic int for reset operation */
+ public static final int OP_RESET = 3;
+
+ /**
+ * Array aligned on int values of possible operations
+ * to provide a string equivalent.
+ */
+ public static final String OPERATION_STRINGS [] = {
+ MODIFY_STR,
+ REPLACE_STR,
+ REMOVE_STR,
+ RESET_STR
+ } ;
+
+ /**
+ * Returns the symbolic int value corresponding to
+ * an operation string.
+ *
+ * @param aOperation string representing the operation
+ * @return int representing the operation
+ */
+ public static int getInt(String aOperation) {
+ for (int i = 0 ; i < OPERATION_STRINGS.length ; ++ i) {
+ if (OPERATION_STRINGS [i].equals(aOperation)) {
+ return i ;
+ }
+ }
+ return OP_UNKNOWN ;
+ }
+ /**
+ * Returns the string value corresponding to an int operation.
+ *
+ * @param aOperation int representing the operation
+ * @return string representing the operation
+ */
+ public static String getString(int aOperation) {
+ if (aOperation >= 0 && aOperation < OPERATION_STRINGS.length) {
+ return OPERATION_STRINGS [aOperation] ;
+ }
+ return null ;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/PolicyTree.java b/src/com/sun/apoc/spi/cfgtree/PolicyTree.java
new file mode 100644
index 0000000..ad3d225
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/PolicyTree.java
@@ -0,0 +1,123 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNode;
+
+/**
+ * Interface for a policy tree.
+ *
+ */
+public interface PolicyTree {
+ public static final int BUFFER_SIZE = 200;
+ public static final String DEFAULT_LOCALE_NAME="default";
+ /** tab length */
+ public static final char TAB = 0x9;
+ /** path name separator */
+ public static final String PATH_SEPARATOR = "/";
+
+ /*
+ * Returns the <code>PolicyNode</code> object representing
+ * the root node.
+ *
+ * @return the <code>PolicyNode</code> object
+ */
+ public PolicyNode getRootNode() ;
+
+ /**
+ * Returns a boolean indicating if the tree has
+ * been modified.
+ *
+ * @return <code>true</code> if the node has been
+ * modified, otherwise <code>false</code>
+ */
+ public boolean hasBeenModified() ;
+
+ /**
+ * Returns the <code>PolicyNode</code> object representing
+ * the data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public PolicyNode getNode(String aPath) throws SPIException ;
+
+ /**
+ * Returns the Policy id for this PolicyTree.
+ *
+ * @return the policy id
+ */
+ public String getPolicyId();
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public PolicyNode createNode(String aPath) throws SPIException ;
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the list element for this data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public PolicyNode createReplaceNode(String aPath)
+ throws SPIException ;
+
+ /**
+ * Returns a boolean indicating if the node for this
+ * data path exists.
+ *
+ * @param aPath node path
+ * @return <code>true</code> if the node exists,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public boolean nodeExists(String aPath) throws SPIException;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/PolicyTreeConverter.java b/src/com/sun/apoc/spi/cfgtree/PolicyTreeConverter.java
new file mode 100644
index 0000000..e87dc9a
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/PolicyTreeConverter.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Interface for a PolicyTree Converter.
+ *
+ */
+public interface PolicyTreeConverter {
+
+ /**
+ * Returns the <code>Policy</code> object derived from the
+ * <code>PolicyTree</code>.
+ *
+ * @param aPolicyTree the policy tree
+ * @return the <code>Policye</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public Policy getPolicy(PolicyTree aPolicyTree)
+ throws SPIException ;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/PolicyTreeException.java b/src/com/sun/apoc/spi/cfgtree/PolicyTreeException.java
new file mode 100644
index 0000000..0cd9c15
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/PolicyTreeException.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.SPIException;
+
+public class PolicyTreeException extends SPIException {
+
+ public PolicyTreeException() {
+ super();
+ }
+
+ public PolicyTreeException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/PolicyTreeFactory.java b/src/com/sun/apoc/spi/cfgtree/PolicyTreeFactory.java
new file mode 100644
index 0000000..ccc8ad6
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/PolicyTreeFactory.java
@@ -0,0 +1,72 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Interface for a policy.
+ *
+ */
+public interface PolicyTreeFactory {
+
+ /**
+ * Returns the <code>PolicyTree</code> object derived from the
+ * <code>Iterator</code> of policies.
+ *
+ * @param aPolicies policies
+ * @return the <code>PolicyTree</code> object
+ * @throws <code>RegistryException</code> if error
+ * occurs
+ */
+ public PolicyTree getPolicyTree(Iterator aPolicies) throws SPIException ;
+
+ /**
+ * Returns the <code>PolicyTree</code> object derived from the
+ * policy.
+ *
+ * @param aPolicy policy object
+ * @return the <code>PolicyTree</code> object
+ * @throws <code>RegistryException</code> if error
+ * occurs
+ */
+ public PolicyTree getPolicyTree(Policy aPolicy) throws SPIException ;
+
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/PolicyTreeFactoryImpl.java b/src/com/sun/apoc/spi/cfgtree/PolicyTreeFactoryImpl.java
new file mode 100644
index 0000000..aea2763
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/PolicyTreeFactoryImpl.java
@@ -0,0 +1,109 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import java.util.Iterator;
+
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.XMLReader;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Abstract class for a PolicyTreeFactory.
+ *
+ */
+public abstract class PolicyTreeFactoryImpl implements PolicyTreeFactory {
+
+ /** The instance of the XMLReader */
+ private XMLReader mReader;
+ /** SAX feature controlling the reporting of Namespace declarations */
+ private static final String SAX_NAMESPACES =
+ "http://xml.org/sax/features/namespaces";
+ /** SAX feature controlling the reporting of Namespace
+ prefixes declarations */
+ private static final String SAX_NAMESPACE_PREFIXES =
+ "http://xml.org/sax/features/namespace-prefixes";
+ /** sax parser factory */
+ private SAXParserFactory mSAXParserFactory;
+ private static final String MODULE = "PolicyTreeFactoryImpl";
+
+ /**
+ * Creates and returns an instance of an XMLReader.
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public XMLReader getXMLReader() throws SPIException {
+ if (mReader == null) {
+ try {
+ mSAXParserFactory = SAXParserFactory.newInstance();
+ mReader = mSAXParserFactory.newSAXParser().getXMLReader();
+ mReader.setFeature(SAX_NAMESPACES, true);
+ mReader.setFeature(SAX_NAMESPACE_PREFIXES,
+ true);
+ } catch (Exception e) {
+ throw new XMLPolicyTreeException(e);
+ }
+ }
+ return mReader;
+ }
+
+ /**
+ * Returns the <code>PolicyTree</code> object derived from the
+ * <code>Iterator</code> of policies.
+ *
+ * @param aPolicies policies
+ * @return the <code>PolicyTree</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public abstract PolicyTree getPolicyTree(Iterator aPolicies) throws SPIException ;
+
+ /**
+ * Returns the <code>PolicyTree</code> object derived from the
+ * policy.
+ *
+ * @param aPolicy policy object
+ * @return the <code>PolicyTree</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public abstract PolicyTree getPolicyTree(Policy aPolicy) throws SPIException ;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/PolicyTreeImpl.java b/src/com/sun/apoc/spi/cfgtree/PolicyTreeImpl.java
new file mode 100644
index 0000000..2265f19
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/PolicyTreeImpl.java
@@ -0,0 +1,286 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.net.URLDecoder;
+import java.io.UnsupportedEncodingException;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.policynode.InvalidPolicyNodeException;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNode;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNodeImpl;
+import com.sun.apoc.spi.policies.MismatchPolicyException;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Abstract class for a policy tree.
+ *
+ */
+public abstract class PolicyTreeImpl implements PolicyTree {
+ private PolicyNodeImpl mRootNode;
+ private Policy mTopPolicy;
+ private static final String MODULE = "PolicyTreeImpl";
+
+ /**
+ * Checks the validity of a layer root node by ensuring
+ * it has a name and the correct package name.
+ *
+ * @param aLayerRootNode the layer root node
+ * @param aPolicyId the policy id
+ * @throws InvalidPolicyNodeException if node is invalid
+ */
+ public void checkLayerRootNodeValidity(
+ PolicyNodeImpl aLayerRootNode,
+ String aPolicyId) throws SPIException {
+ if (aLayerRootNode.getName() == null) {
+ throw new InvalidPolicyNodeException();
+ }
+ /* the update layer should specify the correct package */
+ String packageName = aLayerRootNode.getPackage();
+ String name = aLayerRootNode.getName();
+ if (packageName == null || name == null ||
+ !aPolicyId.endsWith(packageName + "." + name)) {
+ throw new InvalidPolicyNodeException(
+ packageName + "." + name, aPolicyId);
+ }
+ }
+
+ /**
+ * Checks to see that the list of policies have the same
+ * policy id. If not an exception is thrown.
+ *
+ * @param aPolicies list of policies
+ * @throws MismatchPolicyException if don't match
+ */
+ public void checkPolicyIdsMatch(ArrayList aPolicies)
+ throws SPIException {
+ String policyId = ((Policy)aPolicies.get(0)).getId();
+ for (int i = 1; i < aPolicies.size(); ++i) {
+ Policy policy = (Policy)aPolicies.get(i);
+ if (!policy.getId().equalsIgnoreCase(policyId)) {
+ throw new MismatchPolicyException();
+ }
+ }
+ }
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public abstract PolicyNode createNode(String aPath)
+ throws SPIException ;
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the list element for this data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public abstract PolicyNode createReplaceNode(String aPath)
+ throws SPIException ;
+
+ /**
+ * Returns the <code>PolicyNode</code> object representing
+ * the data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public PolicyNode getNode(String aPath) throws SPIException {
+ if (aPath.equals(mRootNode.getAbsolutePath())) { return mRootNode; }
+ StringTokenizer st = new StringTokenizer(aPath,
+ PolicyTree.PATH_SEPARATOR);
+ if (st.hasMoreTokens()) {
+ String policyId = st.nextToken();
+ if (!policyId.equals(mTopPolicy.getId())) {
+ throw new MismatchPolicyException();
+ }
+ }
+ PolicyNodeImpl retCode = mRootNode;
+ while (st.hasMoreTokens()) {
+ retCode = retCode.getChildNode(decodePath(st.nextToken()));
+ if (retCode == null) {
+ return null;
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the <code>Policy</code> for this policy tree.
+ *
+ * @return <code>Policy</code> corresponding to the
+ * top most layer for this policy tree
+ */
+ public Policy getPolicy() {
+ return mTopPolicy;
+ }
+
+ /**
+ * Returns the Policy id for this PolicyTree.
+ *
+ * @return the policy id
+ */
+ public String getPolicyId() {
+ return mTopPolicy.getId();
+ }
+
+ /**
+ * Returns the <code>PolicyNode</code> object representing
+ * the root node.
+ *
+ * @return the <code>PolicyNode</code> object
+ */
+ public PolicyNode getRootNode() {
+ return mRootNode;
+ }
+
+ /**
+ * Returns the top policy for this policy tree.
+ *
+ * @return the top policy
+ *
+ */
+ public Policy getTopPolicy() { return mTopPolicy; }
+
+
+ /**
+ * Returns a boolean indicating if the tree has
+ * been modified.
+ *
+ * @return <code>true</code> if the node has been
+ * modified, otherwise <code>false</code>
+ *
+ */
+ public boolean hasBeenModified() {
+ return mRootNode.hasBeenModified();
+ }
+
+ /**
+ * Returns a boolean indicating if the node for this
+ * data path exists.
+ *
+ * @param aPath node path
+ * @return <code>true</code> if the node exists,
+ * otherwise <code>false</code>
+ *
+ */
+ public boolean nodeExists(String aPath) throws SPIException {
+ if (aPath.equals(mRootNode.getAbsolutePath())) { return true; }
+ StringTokenizer st = new StringTokenizer(aPath,
+ PolicyTree.PATH_SEPARATOR);
+ if (st.hasMoreTokens()) {
+ String policyId = st.nextToken();
+ if (!policyId.equals(mTopPolicy.getId())) {
+ throw new MismatchPolicyException();
+ }
+ }
+ boolean retCode = false;
+ PolicyNodeImpl childNode = mRootNode;
+ int tokens = st.countTokens();
+ for (int i = 0; i < tokens; ++i) {
+ childNode = childNode.getChildNode(decodePath(st.nextToken()));
+ if (childNode != null) {
+ retCode = true;
+ } else {
+ retCode = false;
+ break;
+ }
+ }
+ return retCode;
+ }
+
+ /*
+ * Sets the <code>PolicyNode</code> object representing
+ * the root node.
+ *
+ * @param aRootNode the <code>PolicyNode</code> object
+ */
+ public void setRootNode(PolicyNodeImpl aRootNode) {
+ mRootNode = aRootNode;
+ }
+
+ /**
+ * Sets the top policy for this policy tree.
+ *
+ * @param aTopPolicy the policy id
+ *
+ */
+ public void setTopPolicy(Policy aTopPolicy) {
+ mTopPolicy = aTopPolicy;
+ }
+
+ /**
+ * Helper method for decoding path elements (via URLDecoder).
+ *
+ * At the moment we use the slash '/' to separate the elements of config node
+ * paths (e.g. 'com.sun.apoc/node1/node2'). However, node names might also
+ * include a slash. To correctly identify nodes within a path, we require
+ * that node names with inluded slashes must be encoded/escaped (via
+ * URLEncoder). For example, a node with name 'text/html' might appear as
+ * 'com.sun.apoc/node1/text%2Fhtml' within a path.
+ *
+ * @param pathElement The part of the path that should be decoded.
+ */
+ public static String decodePath(String pathElement) throws SPIException {
+ try {
+ // decoding a string is a somewhat expensive operation. For
+ // performance reasons we therefore check, if decoding is required
+ // at all.
+ if (pathElement.indexOf('%') == -1) {
+ return pathElement;
+ } else {
+ return URLDecoder.decode(pathElement, "UTF-8");
+ }
+ } catch (UnsupportedEncodingException ex) {
+ throw new SPIException(ex);
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/ProtectedElement.java b/src/com/sun/apoc/spi/cfgtree/ProtectedElement.java
new file mode 100644
index 0000000..e564e4d
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/ProtectedElement.java
@@ -0,0 +1,71 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Interface for a protected node.
+ *
+ */
+public interface ProtectedElement {
+
+ /**
+ * Returns a boolean indicating if the node is
+ * protected.
+ *
+ * @return <code>true</code> if the node is protected
+ * otherwise <code>false</code>
+ */
+ public boolean isProtected() ;
+
+ /**
+ * Sets the protected state of this node.
+ *
+ * @param aState boolean value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setProtected(boolean aState) throws SPIException;
+
+ /**
+ * Returns a boolean indicating if the node is
+ * protected.
+ *
+ * @return <code>true</code> if the node is protected
+ * otherwise <code>false</code>
+ */
+ public boolean isReadOnly() ;
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/ProtectedElementImpl.java b/src/com/sun/apoc/spi/cfgtree/ProtectedElementImpl.java
new file mode 100644
index 0000000..31342fd
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/ProtectedElementImpl.java
@@ -0,0 +1,137 @@
+ /*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNode;
+import com.sun.apoc.spi.cfgtree.property.Property;
+
+/**
+ * Abstract class for a protected configuration element.
+ *
+ */
+public abstract class ProtectedElementImpl extends ConfigElementImpl implements ProtectedElement{
+
+ /** boolean indicating whether or not the element is finalized */
+ protected boolean mIsProtected = false;
+ /** boolean indicating whether or not the element is readonly */
+ protected boolean mIsReadOnly = false;
+ /** Module name for exceptions */
+ private static final String MODULE = "ProtectedElementImpl";
+
+ /**
+ * Used when doing an edit to check if an element is readonly, and
+ * if it is then an exception is thrown.
+ *
+ * @throws <code>SPIException</code> if element is
+ * readonly
+ */
+ public void checkIfReadOnly() throws SPIException {
+ if (mIsReadOnly) {
+ String elementType = "ProtectedElement";
+ if (this instanceof PolicyNode) {
+ elementType = "PolicyNode";
+ }
+ else if (this instanceof Property) {
+ elementType = "Property";
+ }
+ throw new ReadOnlyElementException (elementType, getName());
+ }
+ }
+
+ /**
+ * Indicates if the element is finalized.
+ *
+ * @return <code>true</code> if finalized,
+ * otherwise <code>false</code>
+ */
+ public boolean isProtected() { return mIsProtected ; }
+
+ /**
+ * Indicates if the element is readonly.
+ *
+ * @return <code>true</code> if readonly,
+ * otherwise <code>false</code>
+ */
+ public boolean isReadOnly() { return mIsReadOnly ; }
+
+ /**
+ * Set the finalized attribute for the element.
+ *
+ * @param aSetting <code>true</code> or <code>false</code>
+ */
+ public void setFinalized (boolean aSetting) {
+ mIsProtected = aSetting;
+ }
+
+ /**
+ * Sets the value of the finalized property of the element.
+ *
+ * @param aIsProtected <code>true</code> if the element
+ * is finalized, <code>false</code>
+ * otherwise
+ * if aIsProtected is <code>false</code>
+ * @throws <code>SPIException</code> if opeartion
+ * is illegal
+ */
+ public abstract void setProtected(boolean aIsProtected)
+ throws SPIException ;
+
+
+ /**
+ * Sets the readonly flag of the element to true,
+ */
+ public void setReadOnly() {
+ if (mIsProtected) {
+ mIsReadOnly = true;
+ mIsProtected = false;
+ }
+ }
+
+ /**
+ * Returns a shallow copy of the node (excludes child nodes).
+ *
+ * @return copy of the node
+ * @throws <code>SPIException</code> if cannot
+ * create copy
+ */
+ public ConfigElementImpl shallowCopy() throws SPIException {
+ ConfigElementImpl returnNode = super.shallowCopy();
+ ((ProtectedElementImpl)returnNode).mIsProtected = mIsProtected;
+ ((ProtectedElementImpl)returnNode).mIsReadOnly = mIsReadOnly;
+ return returnNode;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/ReadOnlyElementException.java b/src/com/sun/apoc/spi/cfgtree/ReadOnlyElementException.java
new file mode 100644
index 0000000..04a4ef8
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/ReadOnlyElementException.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree;
+
+public class ReadOnlyElementException extends PolicyTreeException {
+
+ private static final String READONLY_POLICYTREE_KEY =
+ "error.spi.policytree.element.readonly";
+
+ protected String mElementName = null;
+ protected String mElementType = null;
+
+ public ReadOnlyElementException () {
+ super();
+ }
+
+ public ReadOnlyElementException (String elementType,
+ String elementName) {
+ super();
+ mElementName = elementName;
+ mElementType = elementType;
+ mMessageKey = READONLY_POLICYTREE_KEY;
+ mMessageParams = new Object[]{mElementType, mElementName};
+ }
+
+ public String getElementName() { return mElementName; }
+ public String getElementType() { return mElementType; }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/ReadWritePolicyTreeFactory.java b/src/com/sun/apoc/spi/cfgtree/ReadWritePolicyTreeFactory.java
new file mode 100644
index 0000000..40de75b
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/ReadWritePolicyTreeFactory.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Interface for a policy.
+ *
+ */
+public interface ReadWritePolicyTreeFactory {
+
+ /**
+ * Returns the read/write <code>PolicyTree</code> object derived from the
+ * <code>Iterator</code> of policies.
+ *
+ * @param aPolicies policies
+ * @return the <code>PolicyTree</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public PolicyTree getPolicyTree(Iterator aPolicies) throws SPIException ;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/XMLPolicyTreeException.java b/src/com/sun/apoc/spi/cfgtree/XMLPolicyTreeException.java
new file mode 100644
index 0000000..40621a4
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/XMLPolicyTreeException.java
@@ -0,0 +1,51 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree;
+
+public class XMLPolicyTreeException extends PolicyTreeException {
+
+ private static final String XML_POLICYTREE_KEY =
+ "error.spi.policytree.xml";
+
+ public XMLPolicyTreeException () {
+ super();
+ mMessageKey = XML_POLICYTREE_KEY;
+ }
+
+ public XMLPolicyTreeException (Throwable cause) {
+ super(cause);
+ mMessageKey = XML_POLICYTREE_KEY;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/XMLStreamable.java b/src/com/sun/apoc/spi/cfgtree/XMLStreamable.java
new file mode 100644
index 0000000..381e17a
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/XMLStreamable.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree;
+
+import java.io.PrintStream;
+
+/**
+ * Interface supported by objects able to print themselves to
+ * an output PrintStream.
+ *
+ */
+public interface XMLStreamable
+{
+ /** Global policy schema format */
+ public static final int POLICY_SCHEMA = 0 ;
+ /** Update schema format */
+ public static final int UPDATE_SCHEMA = 1 ;
+ /** Merged schema format */
+ public static final int MERGED_SCHEMA = 2 ;
+
+ /**
+ * Prints the object's contents to a PrintStream.
+ *
+ * @param aIndent indent prefix to use for the printing
+ * @param aOutput output PrintStream
+ * @param aFormat schema type
+ */
+ public void printToStream(String aIndent,
+ PrintStream aOutput, int aFormat);
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeException.java b/src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeException.java
new file mode 100644
index 0000000..bc59b03
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeException.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree.policynode;
+
+public class InvalidPolicyNodeException extends PolicyNodeException {
+
+ private static final String INVALID_POLICYNODE_KEY =
+ "error.spi.policytree.policynode.invalid";
+ private static final String INCOMPATIBLE_POLICYNODE_KEY =
+ "error.spi.policytree.policynode.incompatible";
+
+ protected String mPolicyNodeName = null;
+
+ public InvalidPolicyNodeException () {
+ super();
+ mMessageKey = INVALID_POLICYNODE_KEY;
+ }
+
+ public InvalidPolicyNodeException (String policynodeName,
+ String policyId) {
+ super();
+ mPolicyNodeName = policynodeName;
+ mMessageKey = INCOMPATIBLE_POLICYNODE_KEY;
+ mMessageParams = new Object[]{mPolicyNodeName, policyId};
+ }
+
+ public String getName() { return mPolicyNodeName; }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeNameException.java b/src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeNameException.java
new file mode 100644
index 0000000..16f489e
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/policynode/InvalidPolicyNodeNameException.java
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree.policynode;
+
+public class InvalidPolicyNodeNameException extends PolicyNodeException {
+
+ private static final String INVALID_NAME_POLICYNODE_KEY =
+ "error.spi.policytree.policynode.name.invalid";
+
+ protected String mName;
+
+ public InvalidPolicyNodeNameException () {
+ super();
+ }
+
+ public InvalidPolicyNodeNameException (String name) {
+ super();
+ mName = name;
+ mMessageKey = INVALID_NAME_POLICYNODE_KEY;
+ mMessageParams = new Object[]{mName};
+ }
+
+ public String getName () { return mName; }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/policynode/MergedPolicyNode.java b/src/com/sun/apoc/spi/cfgtree/policynode/MergedPolicyNode.java
new file mode 100644
index 0000000..02b7e2e
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/policynode/MergedPolicyNode.java
@@ -0,0 +1,64 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.policynode;
+
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Interface for a merged policy node.
+ *
+ */
+public interface MergedPolicyNode extends PolicyNode {
+
+ /**
+ * Returns the <code>Policy</code> object where this node
+ * originated.
+ *
+ * @return <code>Policy</code> where this merged node
+ * originated
+ */
+ public Policy getOrigin() ;
+
+ /**
+ * Returns the <code>Policy</code> object where the
+ * protected attribute originated.
+ *
+ * @return <code>Policy</code> where the protected
+ * attribute originated
+ */
+ public Policy getOriginOfProtection() ;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNode.java b/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNode.java
new file mode 100644
index 0000000..4cd96a3
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNode.java
@@ -0,0 +1,147 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.policynode;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.ProtectedElement;
+import com.sun.apoc.spi.cfgtree.property.Property;
+
+/**
+ * Interface for a policy node.
+ *
+ */
+public interface PolicyNode extends ProtectedElement{
+
+ /**
+ * Returns list of child node names.
+ *
+ * @return array of child node names
+ */
+ public String[] getChildrenNames();
+
+ /**
+ * Clears the properties.
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void clearProperties() throws SPIException;
+
+ /**
+ * Returns the requested property, or null if
+ * it doesn't exist.
+ *
+ * @param aPropertyName
+ * @return property
+ */
+ public Property getProperty(String aPropertyName) ;
+
+ /**
+ * Returns list of property names.
+ *
+ * @return array of property names
+ */
+ public String[] getPropertyNames() ;
+
+ /**
+ * Returns the node name.
+ *
+ * @return the node name
+ */
+ public String getName() ;
+
+ /**
+ * Sets the node name.
+ */
+ public void setName(String aName) ;
+
+ /**
+ * Returns the absolute path for this node.
+ *
+ * @return the absolute path
+ */
+ public String getAbsolutePath() ;
+
+ /**
+ * Returns the parent <code>PolicyNode</code>.
+ *
+ * @return the parent policy node
+ */
+ public PolicyNode getParent() ;
+
+ /**
+ * Adds a new node.
+ *
+ * @param aName name of the node to be added
+ * @return the newly added <code>PolicyNode</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public PolicyNode addNode(String aName) throws SPIException;
+
+ /**
+ * Removes a node.
+ *
+ * @param aName name of the node to be removed
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void removeNode(String aName) throws SPIException;
+
+ /**
+ * Adds a new node with attribute "op=replace".
+ *
+ * @param aName name of the node to be replaced
+ * @return the newly replaced <code>PolicyNode</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public PolicyNode addReplaceNode(String aName) throws SPIException;
+
+ /**
+ * Adds a new <code>Property</code>.
+ *
+ * @param aName name of the property to be added
+ * @return the newly added <code>Property</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Property addProperty(String aName) throws SPIException;
+
+ /**
+ * Removes a <code>Property</code>.
+ *
+ * @param aName name of the property to be removed
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void removeProperty(String aName) throws SPIException;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeException.java b/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeException.java
new file mode 100644
index 0000000..93610e6
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeException.java
@@ -0,0 +1,41 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree.policynode;
+
+import com.sun.apoc.spi.cfgtree.PolicyTreeException;
+
+public class PolicyNodeException extends PolicyTreeException {
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeImpl.java b/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeImpl.java
new file mode 100644
index 0000000..a4221c5
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/policynode/PolicyNodeImpl.java
@@ -0,0 +1,1124 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.policynode;
+
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.net.URLEncoder;
+import java.io.UnsupportedEncodingException;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.ConfigElementImpl;
+import com.sun.apoc.spi.cfgtree.NodeKey;
+import com.sun.apoc.spi.cfgtree.NodeParsing;
+import com.sun.apoc.spi.cfgtree.OperationType;
+import com.sun.apoc.spi.cfgtree.PolicyTree;
+import com.sun.apoc.spi.cfgtree.ProtectedElementImpl;
+import com.sun.apoc.spi.cfgtree.XMLStreamable;
+import com.sun.apoc.spi.cfgtree.property.Property;
+import com.sun.apoc.spi.cfgtree.property.PropertyImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Abstract class for a policy node.
+ *
+ */
+public abstract class PolicyNodeImpl extends ProtectedElementImpl
+ implements PolicyNode, MergedPolicyNode, XMLStreamable {
+
+ /** list of children names */
+ public Vector mAllChildrenNames ;
+ /** hashtable for child nodes */
+ public Hashtable mChildNodeTable ;
+ /** hashtable for child properties */
+ public Hashtable mPropertyTable ;
+ /** vector of child nodes removed during final layer read */
+ public Vector mRemovedChildren ;
+ /** the layer where the node originated */
+ protected Policy mOriginLayer;
+ /** the name of the element, including path, where the finalized
+ attribute was set to true */
+ protected String mNameOfElementWhereProtectionSet;
+ /** the layer where the finalized attribute was set to true */
+ protected Policy mOriginOfProtection;
+ /** Module name for exceptions */
+ private static final String MODULE = "PolicyNodeImpl";
+
+
+ /**
+ * Adds a new child node to the node and
+ * sets the child node's parent.
+ *
+ * @param aChild child node to add
+ */
+ public void addChildNode(PolicyNodeImpl aChild) {
+ /* need to keep a list of all children in order as they
+ appear in the parent node, so use a vector for this. But
+ also need to be able to access a child node by its name, so
+ maintaing a Hashtable in conjunction with the list. */
+ if (aChild == null) { return; }
+ if (mAllChildrenNames == null) { mAllChildrenNames = new Vector() ; }
+ if (mChildNodeTable == null) { mChildNodeTable = new Hashtable() ; }
+ /* need to check if updating an existing child node,
+ or adding a new child node */
+ PolicyNodeImpl originalNode =
+ (PolicyNodeImpl)mChildNodeTable.get(
+ aChild.getName());
+ if (originalNode != null) {
+ int index = mAllChildrenNames.indexOf(originalNode.getName());
+ if (index > -1) {
+ mAllChildrenNames.setElementAt(aChild.getName(), index);
+ } else {
+ mAllChildrenNames.add(aChild.getName());
+ }
+ } else {
+ mAllChildrenNames.add(aChild.getName());
+ }
+ mChildNodeTable.put(aChild.getName(), aChild) ;
+ aChild.setParent(this) ;
+ }
+
+ /**
+ * Adds a new node.
+ *
+ * @param aName name of the node to be added
+ * @return the newly added <code>PolicyNodeImpl</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract PolicyNode addNode(String aName) throws SPIException ;
+
+ /**
+ * Adds a new <code>Property</code>.
+ *
+ * @param aName name of the property to be added
+ * @return the newly added <code>Property</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Property addProperty(String aName) throws SPIException;
+
+
+ /**
+ * Adds a new property to the node and
+ * sets the property's parent.
+ *
+ * @param aProperty property to add
+ */
+ public void addProperty(PropertyImpl aProperty) {
+ /* need to keep a list of all children in order as they
+ appear in the parent node, so use a vector for this. But
+ also need to be able to access a child property by its name, so
+ maintaing a Hashtable in conjunction with the list. */
+ if (aProperty == null) { return; }
+ if (mAllChildrenNames == null) { mAllChildrenNames = new Vector() ; }
+ if (mPropertyTable == null) { mPropertyTable = new Hashtable() ; }
+ /* need to check if updating an existing child property,
+ or adding a new child property */
+ PropertyImpl originalProperty =
+ (PropertyImpl)mPropertyTable.get(
+ aProperty.getName());
+ if (originalProperty != null) {
+ int index = mAllChildrenNames.indexOf(originalProperty.getName());
+ if (index > -1) {
+ mAllChildrenNames.setElementAt(aProperty.getName(), index);
+ } else {
+ mAllChildrenNames.add(aProperty.getName());
+ }
+ } else {
+ mAllChildrenNames.add(aProperty.getName());
+ }
+ mPropertyTable.put(aProperty.getName(), aProperty) ;
+ aProperty.setParent(this) ;
+ }
+
+
+ /**
+ * Adds a new removed child to the node.
+ *
+ * @param aChild removed child to add
+ */
+ public void addRemovedChild(Object aRemovedChild) {
+ if (aRemovedChild == null) { return; }
+ if (mRemovedChildren == null) {
+ mRemovedChildren = new Vector() ;
+ }
+ mRemovedChildren.add(aRemovedChild);
+ }
+
+
+ /**
+ * Traverses a node and changes the finalized settings to
+ * readonly. This is a utility function used in reading
+ * data from the default layers.
+ */
+ public void changeProtectedNodesToReadOnly() {
+ if (isProtected()) {
+ mIsReadOnly = true;
+ mIsProtected = false;
+ }
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ childNode.changeProtectedNodesToReadOnly();
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ property.setReadOnly();
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Used when doing an edit to check if a node or any of its
+ * children are readonly, and if so an exception is thrown.
+ *
+ * @throws <code>SPIException</code> if node
+ * or its children are readonly
+ */
+ public void checkIfNodeOrChildrenReadOnly()
+ throws SPIException {
+ checkIfReadOnly();
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ childNode.checkIfNodeOrChildrenReadOnly();
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ property.checkIfReadOnly();
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Used when doing an edit to check if any of its
+ * properties are readonly, and if so an exception is thrown.
+ *
+ * @throws <code>SPIException</code> if node
+ * or its children are readonly
+ */
+ public void checkIfPropertiesReadOnly()
+ throws SPIException {
+ if (mAllChildrenNames != null && mPropertyTable != null &&
+ !mPropertyTable.isEmpty()) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ property.checkIfReadOnly();
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Used prior to a remove operation to check if a node or any of its
+ * children are readonly or mandatory, and if so an exception is thrown.
+ *
+ * @throws <code>SPIException</code> if node or its
+ * children are readonly or mandatory
+ */
+ public void checkIfNodeOrChildrenReadOnlyOrMandatory()
+ throws SPIException {
+ checkIfReadOnly();
+ checkIfMandatory();
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ childNode.checkIfNodeOrChildrenReadOnlyOrMandatory();
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ property.checkIfReadOnly();
+ property.checkIfMandatory();
+ }
+ }
+
+ }
+ }
+ }
+
+
+ /**
+ * Clears the properties.
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void clearProperties() throws SPIException ;
+
+ /**
+ * Utility function for creating a copy of a
+ * <code>Vector</code> of nodes.
+ *
+ * @param aOriginalList the <code>Vector</code> to be copied
+ * @return new <code>Vector</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public Vector copyNodeVector(Vector aOriginalList)
+ throws SPIException {
+ Vector newList = new Vector();
+ for (int i = 0; i < aOriginalList.size(); i ++) {
+ PolicyNodeImpl newNode =
+ (PolicyNodeImpl)aOriginalList.get(i);
+ if (newNode != null) {
+ newList.add(newNode.deepCopy());
+ }
+ }
+ return newList;
+ }
+
+
+ /**
+ * Returns a deep copy of the node (including child
+ * nodes for hierarchical nodes).
+ *
+ * @return copy of the node
+ * @throws <code>SPIException</code> if cannot
+ * create copy
+ */
+ public PolicyNodeImpl deepCopy() throws SPIException {
+ PolicyNodeImpl returnNode = (PolicyNodeImpl)shallowCopy();
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ if (name != null) {
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode = (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ returnNode.addChildNode(childNode.deepCopy());
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ returnNode.addProperty(
+ (PropertyImpl)property.shallowCopy());
+ }
+ }
+ }
+ }
+ }
+ return returnNode;
+ }
+
+ /**
+ * Deletes this node.
+ *
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public void delete() throws SPIException {
+ /* if the set is marked readonly, then the
+ operation cannot proceed */
+ checkIfReadOnly();
+ /* if the node or its children are readonly
+ or mandatory then the node cannot be removed */
+ checkIfNodeOrChildrenReadOnlyOrMandatory();
+ /* set the operation attribute to "remove" */
+ setOperationType(OperationType.OP_REMOVE);
+ }
+
+ /**
+ * Utility function for deleting a child node.
+ *
+ * @param aChildName name of node to be deleted
+ */
+ public void deleteChildNode(String aChildName) {
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode = (PolicyNodeImpl)mChildNodeTable.get(aChildName);
+ if (childNode != null) {
+ mChildNodeTable.remove(aChildName);
+ }
+ }
+ if (childNode != null && mAllChildrenNames != null) {
+ mAllChildrenNames.remove(aChildName);
+ }
+ }
+
+ /**
+ * Utility function for deleting a property.
+ *
+ * @param aProperty property to be deleted
+ */
+ public void deleteProperty(PropertyImpl aProperty) {
+ if (aProperty == null) { return; }
+ if (mPropertyTable != null) {
+ mPropertyTable.remove(aProperty.getName());
+ }
+ if (mAllChildrenNames != null) {
+ mAllChildrenNames.remove(aProperty.getName());
+ }
+ }
+
+ /**
+ * Expands the base source layer node.
+ *
+ * @param aNodePath the name of this node, including path
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void expand(String aNodePath, boolean aIsParentUpdateLayer)
+ throws SPIException {
+ mPath = aNodePath;
+ if (isProtected()) {
+ if (getParent() == null ||
+ !getParent().isProtected()){
+ setFinalized(true, getAbsolutePath(),
+ getOriginOfProtection());
+ }
+ if (aIsParentUpdateLayer) {
+ setReadOnly();
+ }
+ }
+ if (mPropertyTable != null) {
+ Enumeration properties = mPropertyTable.elements();
+ while (properties.hasMoreElements()) {
+ PropertyImpl property = (PropertyImpl)properties.nextElement();
+ String propertyPath = appendToPath(aNodePath, property.getName());
+ property.expand(propertyPath, aIsParentUpdateLayer);
+ }
+ }
+ if (mChildNodeTable != null) {
+ Enumeration nodes = mChildNodeTable.elements();
+ while (nodes.hasMoreElements()) {
+ PolicyNodeImpl childNode = (PolicyNodeImpl)nodes.nextElement();
+ String childNodePath = appendToPath(aNodePath, childNode.getName());
+ childNode.expand(childNodePath, aIsParentUpdateLayer);
+ }
+ }
+ }
+
+
+ /**
+ * Returns the list of names for all the children.
+ *
+ * @return the list of child names
+ */
+ public Vector getAllChildrenNames() { return mAllChildrenNames; }
+
+ /**
+ * Returns a string representing the attributes of
+ * the node.
+ *
+ * @param aFormat schema type
+ * @return attribute string
+ */
+ public String getAttributes(int aFormat) {
+ StringBuffer retCode = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ retCode.append(NodeParsing.NAME_ATTR).append("=\"").append(mName);
+ retCode.append("\"");
+ if (getPackage() != null) {
+ retCode.append(" ").append(NodeParsing.PACKAGE_ATTR).append(
+ "=\"").append(getPackage()).append("\"") ;
+ }
+ String operationProp = OperationType.getString(getOperationType());
+ switch (aFormat) {
+ case UPDATE_SCHEMA:
+ case POLICY_SCHEMA:
+ if (isProtected()) {
+ if (getParent() == null ||
+ !((PolicyNodeImpl)getParent()).isProtected()) {
+ retCode.append(" ").append(
+ NodeParsing.FINALIZED_ATTR).append(
+ "=\"true\"") ;
+ }
+ }
+ if (aFormat == UPDATE_SCHEMA && isMandatory()) {
+ if ((getOriginOfMandatory()).equals(
+ getPolicyTree().getPolicy())) {
+ retCode.append(" ");
+ retCode.append(NodeParsing.MANDATORY_ATTR);
+ retCode.append("=\"true\"") ;
+ }
+ }
+ if (aFormat == POLICY_SCHEMA && isMandatory()) {
+ retCode.append(" ");
+ retCode.append(NodeParsing.MANDATORY_ATTR);
+ retCode.append("=\"true\"") ;
+ }
+ if (operationProp != null) {
+ switch(OperationType.getInt(operationProp)) {
+ case OperationType.OP_REPLACE:
+ case OperationType.OP_REMOVE:
+ retCode.append(" ").append(
+ NodeParsing.OPERATION_ATTR).append(
+ "=\"").append(operationProp).append("\"");
+ break;
+ };
+ }
+ break;
+ case MERGED_SCHEMA:
+ if (isReadOnly()) {
+ retCode.append(" ").append(
+ NodeParsing.READONLY_ATTR).append("=\"true\"") ;
+ } else if (isProtected()) {
+ retCode.append(" ").append(
+ NodeParsing.FINALIZED_ATTR).append("=\"true\"") ;
+ }
+ if (isMandatory()) {
+ retCode.append(" ").append(
+ NodeParsing.MANDATORY_ATTR).append(
+ "=\"true\"") ;
+ }
+ if (operationProp != null ) {
+ retCode.append(" ").append(
+ NodeParsing.OPERATION_ATTR).append("=\"").append(
+ operationProp).append("\"");
+ }
+ break;
+ };
+ return retCode.toString();
+ }
+
+
+ /**
+ * Returns a node child designated by its name.
+ *
+ * @param aName name of the child
+ * @return child if it exists, null otherwise
+ */
+ public PolicyNodeImpl getChild(String aName) {
+ if (aName == null || mAllChildrenNames == null ||
+ mChildNodeTable == null) { return null ; }
+ return (PolicyNodeImpl) mChildNodeTable.get(aName) ;
+ }
+
+ /**
+ * Returns an <code>Iterator</code> listing
+ * the policy node children.
+ *
+ * @return iterator on the children list
+ */
+ public Iterator getChildNodes() {
+ if (mChildNodeTable == null ||
+ mChildNodeTable.isEmpty()) {
+ return new Vector().iterator() ;
+ }
+ Vector nodeList = new Vector();
+ for (int i = 0; i < mAllChildrenNames.size(); ++i) {
+ String name = (String)mAllChildrenNames.get(i);
+ PolicyNodeImpl policyNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (policyNode != null) {
+ nodeList.add(policyNode);
+ }
+ }
+ return nodeList.iterator() ;
+ }
+
+ /**
+ * Returns the requested child node, or null if
+ * it doesn't exist.
+ *
+ * @param aChildName
+ * @return child node
+ */
+ public PolicyNodeImpl getChildNode(String aChildName) {
+ if (mChildNodeTable == null ||
+ mChildNodeTable.isEmpty()) {
+ return null;
+ }
+ return (PolicyNodeImpl)mChildNodeTable.get(aChildName);
+ }
+
+ /**
+ * Returns the table of child nodes.
+ *
+ * @return the table of child nodes
+ */
+ public Hashtable getChildNodeTable() { return mChildNodeTable; }
+
+
+ /**
+ * Returns list of child node names.
+ *
+ * @return array of child node names
+ */
+ public String[] getChildrenNames() {
+ if (mChildNodeTable == null ||
+ mChildNodeTable.isEmpty()) {
+ return new String[0];
+ }
+ String[] retCode = new String[mChildNodeTable.size()];
+ Enumeration names = mChildNodeTable.keys();
+ int index = 0;
+ while (names.hasMoreElements()) {
+ retCode[index++] = (String)names.nextElement();
+ }
+ return retCode;
+ }
+
+ /**
+ * Gets the name of the element (including path) where the finalized
+ * attribute was set.
+ *
+ * @return name of the element, including path
+ */
+ public String getNameOfElementWhereProtectionSet() {
+ return mNameOfElementWhereProtectionSet;
+ }
+
+ /**
+ * Returns the policy where the element
+ * originated.
+ *
+ * @return the policy where the element originated
+ */
+ public Policy getOrigin() { return mOriginLayer; }
+
+ /**
+ * Gets the policy where the finalized attribute
+ * was set.
+ *
+ * @return the policy where the attribute was set
+ */
+ public Policy getOriginOfProtection() {
+ return mOriginOfProtection;
+ }
+
+ /**
+ * Returns an <code>Iterator</code> listing
+ * the property children.
+ *
+ * @return iterator of child properties
+ */
+ public Iterator getProperties() {
+ if (mPropertyTable == null ||
+ mPropertyTable.isEmpty()) {
+ return new Vector().iterator() ;
+ }
+ Vector propertyList = new Vector();
+ for (int i = 0; i < mAllChildrenNames.size(); ++i) {
+ String name = (String)mAllChildrenNames.get(i);
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ propertyList.add(property);
+ }
+ }
+ return propertyList.iterator() ;
+ }
+
+ /**
+ * Returns the requested property, or null if
+ * it doesn't exist.
+ *
+ * @param aPropertyName
+ * @return property
+ */
+ public Property getProperty(String aPropertyName) {
+ if (mPropertyTable == null ||
+ mPropertyTable.isEmpty()) {
+ return null;
+ }
+ return (PropertyImpl)mPropertyTable.get(aPropertyName);
+ }
+
+
+ /**
+ * Returns list of property names.
+ *
+ * @return array of property names
+ */
+ public String[] getPropertyNames() {
+ if (mPropertyTable == null ||
+ mPropertyTable.isEmpty()) {
+ return new String[0];
+ }
+ String[] retCode = new String[mPropertyTable.size()];
+ Enumeration names = mPropertyTable.keys();
+ int index = 0;
+ while (names.hasMoreElements()) {
+ retCode[index++] = (String)names.nextElement();
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the table of properties.
+ *
+ * @return the table of properties
+ */
+ public Hashtable getPropertyTable() { return mPropertyTable; }
+
+
+ /**
+ * Prints the children of the node.
+ *
+ * @param aIndent indent prefix for the children
+ * @param aOutput output stream
+ * @param aFormat schema type
+ */
+ public void printChildren(String aIndent,
+ PrintStream aOutput, int aFormat) {
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ childNode.printToStream(
+ aIndent, aOutput, aFormat);
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ property.printToStream(
+ aIndent, aOutput, aFormat);
+ }
+ }
+
+ }
+ }
+ }
+
+ public static final String XML_HEADER =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" ;
+ private static final String COMPONENT_NAMESPACE =
+ " xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"";
+ /**
+ * Prints the tag of the node (opening or closing).
+ *
+ * @param aIndent indent prefix for the tag
+
+ public static final String XML_HEADER =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" ;
+ private static final String COMPONENT_NAMESPACE =
+ " xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"";
+ /**
+ * Prints the tag of the node (opening or closing).
+ *
+ * @param aIndent indent prefix for the tag
+ * @param aOutput output stream
+ * @param aOpening true if opening tag, false otherwise
+ * @param aFormat schema type
+ */
+ public void printTag(String aIndent, PrintStream aOutput,
+ boolean aOpening, int aFormat) {
+ if (aOpening && getParent() == null) {
+ aOutput.print(XML_HEADER) ;
+ }
+ aOutput.print(aIndent + (aOpening ? "<" : "</")) ;
+ switch(aFormat) {
+ case UPDATE_SCHEMA:
+ case POLICY_SCHEMA:
+ /* if this is the component node, then
+ the tag is "<oor:component-data" */
+ if (getParent() == null) {
+ aOutput.print(NodeParsing.OOR_NAMESPACE);
+ aOutput.print(NodeParsing.COMPONENT_DATA_TAG) ;
+ if (aOpening) {
+ aOutput.print(COMPONENT_NAMESPACE);
+ }
+ } else {
+ aOutput.print(NodeParsing.NODE_TAG) ;
+ }
+ break;
+ case MERGED_SCHEMA:
+ aOutput.print(NodeParsing.NODE_TAG) ;
+ break;
+ }
+ if (aOpening) {
+ aOutput.print(" " + getAttributes(aFormat)) ;
+ }
+ aOutput.print(">\n") ;
+ }
+
+ /**
+ * Outputs the node's contents to a PrintStream.
+ *
+ * @param aIndent indent prefix for the printing
+ * @param aOutput stream to print to
+ * @param aFormat schema type
+ */
+ public void printToStream(String aIndent,
+ PrintStream aOutput, int aFormat) {
+ printTag(aIndent, aOutput, true, aFormat) ;
+ printChildren(aIndent + PolicyTree.TAB, aOutput, aFormat) ;
+ printTag(aIndent, aOutput, false, aFormat) ;
+ }
+
+ /**
+ * Carries out the read merge modification operation specified in
+ * this update node.
+ *
+ * @param aResultNode node that will be the result of
+ * the read merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public abstract void readModifyNode(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException ;
+
+ /**
+ * Carries out the removal operation specified in
+ * this update node. For a read merge this operation
+ * results in the deletion of specified subnodes of a
+ * set.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public abstract void readRemoveNode(PolicyNodeImpl aResultNode,
+ String aUpdateNodePath, boolean aIsParentUpdateLayer)
+ throws SPIException ;
+
+ /**
+ * Carries out the replacement operation specified in
+ * this update node. This operation can only be applied
+ * to dynamic elements. The replace operation can either
+ * insert a new node or replace a node that already exists.
+ * The corresponding node from the source layer is ignored.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void readReplaceNode(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException ;
+
+ /**
+ * Removes a node.
+ *
+ * @param aName name of the node to be removed
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void removeNode(String aName) throws SPIException;
+
+
+ /**
+ * Removes a <code>Property</code>.
+ *
+ * @param aName name of the property to be removed
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void removeProperty(String aName) throws SPIException;
+
+
+ /**
+ * Adds a new node with attribute "op=replace".
+ *
+ * @param aName name of the node to be replaced
+ * @return the newly replaced <code>PolicyNodeImpl</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract PolicyNode addReplaceNode(String aName)
+ throws SPIException;
+
+
+ /**
+ * Set the finalized attribute for the property.
+ *
+ * @param aSetting <code>true</code> or <code>false</code>
+ * @param aNameOfElementWhereProtectionSet
+ * @param aOriginOfProtection
+ */
+ public void setFinalized (boolean aSetting,
+ String aNameOfElementWhereProtectionSet,
+ Policy aOriginOfProtection) {
+ super.setFinalized(aSetting);
+ mNameOfElementWhereProtectionSet = aNameOfElementWhereProtectionSet;
+ mOriginOfProtection = aOriginOfProtection;
+ if (mChildNodeTable != null) {
+ Enumeration nodes = mChildNodeTable.elements();
+ while (nodes.hasMoreElements()) {
+ PolicyNodeImpl node = (PolicyNodeImpl)nodes.nextElement();
+ node.setFinalized(aSetting,
+ aNameOfElementWhereProtectionSet,
+ aOriginOfProtection);
+ }
+ }
+ if (mPropertyTable != null) {
+ Enumeration properties = mPropertyTable.elements();
+ while (properties.hasMoreElements()) {
+ PropertyImpl property = (PropertyImpl)properties.nextElement();
+ property.setFinalized(aSetting,
+ aNameOfElementWhereProtectionSet,
+ aOriginOfProtection);
+ }
+ }
+ }
+
+ /**
+ * Sets the layer where the node originated.
+ *
+ * @param aOriginLayer id of the layer where the node originated
+ */
+ public void setOrigin (Policy aOriginLayer) {
+ mOriginLayer = aOriginLayer;
+ }
+
+ /**
+ * Sets the readonly flag of the node and its children to true,
+ */
+ public void setReadOnly() {
+ if (mIsProtected) {
+ mIsReadOnly = true;
+ mIsProtected = false;
+ }
+ if (mChildNodeTable != null) {
+ Enumeration nodes = mChildNodeTable.elements();
+ while (nodes.hasMoreElements()) {
+ PolicyNodeImpl node = (PolicyNodeImpl)nodes.nextElement();
+ node.setReadOnly();
+ }
+ }
+ if (mPropertyTable != null) {
+ Enumeration properties = mPropertyTable.elements();
+ while (properties.hasMoreElements()) {
+ PropertyImpl property = (PropertyImpl)properties.nextElement();
+ property.setReadOnly();
+ }
+ }
+ }
+
+ /**
+ * Sets the path, originating layer and dynamic
+ * settings for this node and its children.
+ *
+ * @param aPath path name for this node
+ * @param aOriginLayer layer where node originated
+ * @param aIsParentLayer <code>true</code> true if
+ * data sourced from parent layer,
+ * otherwise <code>false</code>
+ */
+ public void setSettingsForAddedNode(String aPath,
+ Policy aOriginLayer,
+ boolean aIsParentLayer ) throws SPIException {
+ setPath(aPath);
+ if (aOriginLayer != null) { setOrigin(aOriginLayer); }
+ if (!aIsParentLayer) {
+ setAddedAtTopLayer();
+ }
+ String pathName = null;
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ pathName = appendToPath(aPath, childNode.getName());
+ childNode.setSettingsForAddedNode(pathName,
+ aOriginLayer, aIsParentLayer);
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ pathName = appendToPath(aPath, property.getName());
+ property.setSettingsForAddedProperty(pathName,
+ aOriginLayer, aIsParentLayer);
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Returns a shallow copy of the node (excludes child nodes).
+ *
+ * @return copy of the node
+ * @throws <code>SPIException</code> if cannot
+ * create copy
+ */
+ public ConfigElementImpl shallowCopy() throws SPIException {
+ ConfigElementImpl returnNode = super.shallowCopy();
+ if (mRemovedChildren != null) {
+ ((PolicyNodeImpl)returnNode).mRemovedChildren =
+ copyNodeVector(mRemovedChildren);
+ }
+ ((PolicyNodeImpl)returnNode).mNameOfElementWhereProtectionSet =
+ mNameOfElementWhereProtectionSet;
+ ((PolicyNodeImpl)returnNode).mOriginOfProtection =
+ mOriginOfProtection;
+ ((PolicyNodeImpl)returnNode).mOriginLayer =
+ mOriginLayer;
+ return returnNode;
+ }
+
+ /**
+ * Determines from this update node which operation is to
+ * be carried out during the read merge, and then invokes
+ * the corresponding operation method.
+ *
+ * @param aResultNode node that will be the result of
+ * the read merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ * @throws InvalidPolicyNodeException if node is invalid
+ */
+ public void processReadOperation(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException {
+ /* Check the validity of the configuration node */
+ if (mName == null ) {
+ throw new InvalidPolicyNodeException();
+ }
+ /* determine the operation to be carried out */
+ switch (mOperationType) {
+ case OperationType.OP_REPLACE:
+ readReplaceNode(aResultNode, aUpdateNodeKey,
+ aUpdateNodePath, aIsParentUpdateLayer);
+ break;
+ case OperationType.OP_REMOVE:
+ readRemoveNode(aResultNode, aUpdateNodePath,
+ aIsParentUpdateLayer);
+ break;
+ case OperationType.OP_UNKNOWN: //defaults to OP_MODIFY
+ case OperationType.OP_MODIFY:
+ readModifyNode(aResultNode, aUpdateNodeKey,
+ aUpdateNodePath, aIsParentUpdateLayer);
+ break;
+ };
+ }
+
+ /**
+ * Helper method for creating config node paths.
+ *
+ * At the moment we use the slash '/' to separate the elements of config node
+ * paths (e.g. 'com.sun.apoc/node1/node2'). However, node names might also
+ * include a slash. To correctly identify nodes within a path, we require
+ * that node names with inluded slashes must be encoded/escaped (via
+ * URLEncoder). For example, a node with name 'text/html' might appear as
+ * 'com.sun.apoc/node1/text%2Fhtml' within a path.
+ *
+ * The helper method takes care of the neccessary encoding (if required)
+ * before appending the node name to the path.
+ *
+ * @param path An existing node path (or empty string)
+ * @param newElement Typically the name of a node that should be appended
+ * to the existing path.
+ */
+ public static String appendToPath(String path, String newElement)
+ throws SPIException {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(path);
+ buffer.append(PolicyTree.PATH_SEPARATOR);
+ try {
+ // endcoding a string is a somewhat expensive operation. For
+ // performance reasons we therefore check, if encoding is required
+ // at all.
+ if (newElement.indexOf('/') != -1) {
+ buffer.append(URLEncoder.encode(newElement, "UTF-8"));
+ } else {
+ buffer.append(newElement);
+ }
+ } catch (UnsupportedEncodingException ex) {
+ throw new SPIException(ex);
+ }
+ return buffer.toString();
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/policynode/ReadWritePolicyNodeImpl.java b/src/com/sun/apoc/spi/cfgtree/policynode/ReadWritePolicyNodeImpl.java
new file mode 100644
index 0000000..ee9184f
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/policynode/ReadWritePolicyNodeImpl.java
@@ -0,0 +1,1059 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.policynode;
+
+import java.util.Enumeration;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.ConfigElementImpl;
+import com.sun.apoc.spi.cfgtree.NodeKey;
+import com.sun.apoc.spi.cfgtree.OperationType;
+import com.sun.apoc.spi.cfgtree.property.InvalidPropertyNameException;
+import com.sun.apoc.spi.cfgtree.property.Property;
+import com.sun.apoc.spi.cfgtree.property.PropertyImpl;
+import com.sun.apoc.spi.cfgtree.property.ReadWritePropertyImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Class for a read write policy node.
+ *
+ */
+public class ReadWritePolicyNodeImpl extends PolicyNodeImpl {
+
+ public static final String ID_SEPARATOR = ".";
+
+ /** default node - used for reset */
+ public ReadWritePolicyNodeImpl mDefaultNode;
+ private boolean mHasBeenModified = false;
+
+ /**
+ * Adds a new node.
+ *
+ * @param aName name of the node to be added
+ * @return the newly added <code>ReadWritePolicyNodeImpl</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public PolicyNode addNode(String aName) throws SPIException {
+ return addNode(aName, false);
+ }
+
+ /**
+ * Adds a new node. Operation attribute is set to true if
+ * appropriate.
+ *
+ * @param aName name of the node to be added
+ * @param aIsReplaceOp <code>true</code> if operation attribute
+ * should be set, otherwise <code>false</code>
+ * @return the newly added <code>ReadWritePolicyNodeImpl</code>
+ * @throws SPIException if error occurs
+ * @throws InvalidPolicyNodeNameException if aName is null
+ */
+ public PolicyNode addNode(String aName, boolean aIsReplaceOp)
+ throws SPIException {
+ if (aName == null) {
+ throw new InvalidPolicyNodeNameException(aName);
+ }
+ checkIfReadOnly();
+ ReadWritePolicyNodeImpl newNode = new ReadWritePolicyNodeImpl();
+ newNode.setName(aName);
+ newNode.setSettingsForAddedNode(appendToPath(getAbsolutePath(), aName),
+ mPolicyTree.getPolicy(), false);
+ newNode.mPolicyTree = mPolicyTree;
+ if (aIsReplaceOp) {
+ newNode.setOperationType(OperationType.OP_REPLACE);
+ }
+ addChildNode(newNode);
+ mHasBeenModified = true;
+ return newNode;
+ }
+
+ /**
+ * Sets default nodes for nodes in the tree. Used for the
+ * base source layer during a read merge.
+ *
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public void addNodeDefaults() throws SPIException {
+ setDefaultNode((ReadWritePolicyNodeImpl)shallowCopy()) ;
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ ReadWritePolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode =
+ (ReadWritePolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ childNode.addNodeDefaults();
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ ReadWritePropertyImpl property =
+ (ReadWritePropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ property.setDefaultProperty(
+ (ReadWritePropertyImpl)property.shallowCopy()) ;
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Creates and adds a property node to this node.
+ *
+ * @param aPropertyName name of new property
+ * @return the new node
+ * @throws SPIException if error occurs
+ * @throws InvalidPropertyNameException if aName is null
+ */
+ public Property addProperty(String aPropertyName)
+ throws SPIException{
+ if (aPropertyName == null) {
+ throw new InvalidPropertyNameException(aPropertyName);
+ }
+ /* if this node is marked readonly then the property
+ cannot be added */
+ checkIfReadOnly();
+ ReadWritePropertyImpl property = new ReadWritePropertyImpl();
+ property.setName(aPropertyName);
+ property.setAddedAtTopLayer();
+ property.setPath(appendToPath(getAbsolutePath(), aPropertyName));
+ if (isProtected()) {
+ property.setFinalized(true, getAbsolutePath(),
+ getOriginOfProtection());
+ }
+ property.setPolicyTree(mPolicyTree);
+ addProperty(property);
+ mHasBeenModified = true;
+ return property;
+ }
+
+ /**
+ * Creates and adds a property node to this node.
+ *
+ * @param aPropertyName name of new property
+ * @param aOriginLayer layer for which a
+ * node is being added
+ * @return the new node
+ * @throws SPIException if error occurs
+ * @throws InvalidPropertyNameException if aName is null
+ */
+ public ReadWritePropertyImpl addProperty(String aPropertyName,
+ Policy aOriginLayer) throws SPIException{
+ if (aPropertyName == null) {
+ throw new InvalidPropertyNameException(aPropertyName);
+ }
+ /* if this node is marked readonly then the property
+ cannot be added */
+ checkIfReadOnly();
+ ReadWritePropertyImpl property = new ReadWritePropertyImpl();
+ property.setName(aPropertyName);
+ property.setAddedAtTopLayer();
+ property.setOrigin(aOriginLayer);
+ property.setPath(appendToPath(getAbsolutePath(), aPropertyName));
+ if (isProtected()) {
+ property.setFinalized(true, getAbsolutePath(),
+ getOriginOfProtection());
+ }
+ addProperty(property);
+ mHasBeenModified = true;
+ return property;
+ }
+
+ /**
+ * Adds a node with attribute "op=replace".
+ *
+ * @param aName name of the node to be replaced
+ * @return the newly replaced <code>ReadWritePolicyNodeImpl</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public PolicyNode addReplaceNode(String aName) throws SPIException {
+ return addNode(aName, true);
+ }
+
+
+ /**
+ * Clears the settings added at this layer.
+ *
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void clear() throws SPIException {
+ /* cannot apply reset operation if node or one
+ of its children is readonly */
+ checkIfNodeOrChildrenReadOnly();
+ ReadWritePolicyNodeImpl defaultNode = mDefaultNode;
+ PolicyNodeImpl parent = (PolicyNodeImpl)getParent();
+ if (defaultNode != null) {
+ setNodeAndChildrenToDefault(defaultNode);
+ defaultNode.setOperationType(OperationType.OP_RESET);
+ /* replace the node in the policy tree with
+ the default node. */
+ if (parent != null) {
+ if (parent.isProtected()) {
+ defaultNode.setFinalized(true,
+ getNameOfElementWhereProtectionSet(),
+ getOriginOfProtection());
+ }
+ parent.addChildNode(defaultNode);
+ }
+ } else {
+ /* we are dealing with a node added at this layer */
+ checkIfMandatory();
+ setOperationType(OperationType.OP_REMOVE);
+ }
+ mHasBeenModified = true;
+ }
+
+ /**
+ * Clears the properties.
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void clearProperties() throws SPIException {
+ checkIfReadOnly();
+ checkIfPropertiesReadOnly();
+ if (mPropertyTable == null || mPropertyTable.isEmpty()) { return; }
+ Enumeration values = mPropertyTable.elements();
+ while (values.hasMoreElements()) {
+ ReadWritePropertyImpl property = (ReadWritePropertyImpl)values.nextElement();
+ PropertyImpl defaultProperty = property.getDefaultProperty();
+ if (defaultProperty != null) {
+ addProperty(defaultProperty);
+ } else {
+ removeProperty(property.getName());
+ }
+ }
+ mHasBeenModified = true;
+ }
+
+
+ /**
+ * Returns the default node, that is the node as it was in the
+ * default layer.
+ *
+ * @return the default node
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ReadWritePolicyNodeImpl getDefaultNode() throws SPIException {
+ return ( (mDefaultNode != null) ? (ReadWritePolicyNodeImpl)mDefaultNode.shallowCopy() : null);
+ }
+
+ /**
+ * Returns a boolean indicating if the node has
+ * been modified.
+ *
+ * @return <code>true</code> if the node has been
+ * modified, otherwise <code>false</code>
+ */
+ public boolean hasBeenModified() {
+ if (mHasBeenModified) { return mHasBeenModified; }
+ if (mAllChildrenNames != null &&
+ !mAllChildrenNames.isEmpty()) {
+ for (int i = 0 ; i < mAllChildrenNames.size(); ++i) {
+ String name = (String)mAllChildrenNames.get(i);
+ ReadWritePolicyNodeImpl policyNode = null;
+ if (mChildNodeTable != null && !mChildNodeTable.isEmpty()) {
+ policyNode =
+ (ReadWritePolicyNodeImpl)mChildNodeTable.get(name);
+ if (policyNode != null) {
+ if (policyNode.hasBeenModified()) {
+ return true;
+ }
+ }
+ }
+ if (policyNode == null && mPropertyTable != null &&
+ !mPropertyTable.isEmpty()) {
+ ReadWritePropertyImpl property =
+ (ReadWritePropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ if (property.hasBeenModified()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return mHasBeenModified;
+ }
+
+
+ /**
+ * Carries out the update merge operations specified in
+ * this node's children.
+ *
+ * @param aOutputNode the equivalent node for the new
+ * update layer
+ * @param aLayer layer to update
+ * @param aUpdateNodePath the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if any node children
+ * are required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean processUpdateNodeChildren(PolicyNodeImpl aOutputNode,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ boolean update = false;
+ /* if this layer removed any elements,
+ then add these nodes (with op=remove) to the
+ output child node */
+ if (mRemovedChildren != null) {
+ for (int i = 0; i < mRemovedChildren.size(); i++) {
+ Object removedChild =
+ mRemovedChildren.get(i);
+ if (removedChild != null) {
+ if (removedChild instanceof PolicyNodeImpl) {
+ aOutputNode.addChildNode(
+ (PolicyNodeImpl)((PolicyNodeImpl)removedChild).shallowCopy());
+ update = true;
+ } else if (removedChild instanceof PropertyImpl) {
+ aOutputNode.addProperty(
+ (PropertyImpl)((PropertyImpl)removedChild).shallowCopy());
+ update = true;
+ }
+ }
+ }
+ }
+ boolean childUpdate = false;
+ if (mAllChildrenNames != null) {
+ int size = mAllChildrenNames.size();
+ for (int i = 0; i < size; i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ String updatePath = null;
+ PolicyNodeImpl updateNode = null;
+ if (mChildNodeTable != null) {
+ updateNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (updateNode != null) {
+ PolicyNodeImpl outputChildNode =
+ (PolicyNodeImpl)updateNode.shallowCopy();
+ aOutputNode.addChildNode(outputChildNode);
+ updatePath = appendToPath(aUpdateNodePath, updateNode.getName());
+ childUpdate = ((ReadWritePolicyNodeImpl)updateNode)
+ .processUpdateOperation(outputChildNode,
+ aLayer,
+ updatePath);
+ /* if one or more children are required, then update
+ required is set to true */
+ if (!childUpdate) {
+ ((PolicyNodeImpl)aOutputNode).deleteChildNode(
+ outputChildNode.getName());
+ } else {
+ update = true;
+ }
+ }
+ }
+ if (updateNode == null && mPropertyTable != null) {
+ PropertyImpl property = (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ updatePath = appendToPath(aUpdateNodePath, property.getName());
+ PropertyImpl outputProperty =
+ (PropertyImpl)property.shallowCopy();
+ aOutputNode.addProperty(outputProperty);
+ childUpdate = ((ReadWritePropertyImpl)property)
+ .processUpdateOperation(outputProperty, aLayer,
+ updatePath);
+ /* if one or more children are required, then update
+ required is set to true */
+ if (!childUpdate) {
+ ((PolicyNodeImpl)aOutputNode).deleteProperty(
+ outputProperty);
+ } else {
+ update = true;
+ }
+ }
+ }
+ }
+ }
+ return update || childUpdate;
+ }
+
+
+ /**
+ * Determines from this update node which operation is to
+ * be carried out during the read merge, and then invokes
+ * the corresponding operation method.
+ *
+ * @param aOutputNode the equivalent node for the new
+ * update layer
+ * @param aLayer layer to update
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public boolean processUpdateOperation(PolicyNodeImpl aOutputNode,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ boolean update = false;
+ switch (mOperationType) {
+ case OperationType.OP_REPLACE:
+ update = updateReplaceNode(aOutputNode, aLayer,
+ aUpdateNodePath);
+ break;
+ case OperationType.OP_REMOVE:
+ update = updateRemoveNode(aOutputNode, aLayer,
+ aUpdateNodePath);
+ break;
+ case OperationType.OP_RESET:
+ update = updateResetNode(aOutputNode, aLayer,
+ aUpdateNodePath);
+ break;
+ case OperationType.OP_UNKNOWN: //defaults to OP_MODIFY
+ case OperationType.OP_MODIFY:
+ update = updateModifyNode(aOutputNode, aLayer,
+ aUpdateNodePath);
+ break;
+ };
+ return update;
+ }
+
+ /**
+ * Carries out the read merge modification operation specified in
+ * this update node.
+ *
+ * @param aResultNode node that will be the result of
+ * the read merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public void readModifyNode(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException {
+ /* If the node exists in the source layer and is
+ marked readonly there then no processing takes place.*/
+ PolicyNodeImpl resultNode =
+ (PolicyNodeImpl)aResultNode.getChild(getName());
+ if (resultNode != null) {
+ if ( resultNode.isReadOnly()) { return; }
+ /* if the update node is mandatory, then set
+ this flag (and source) on the resulting node */
+ if (isMandatory()) {
+ resultNode.setMandatoryFlag();
+ resultNode.setOriginOfMandatory(getOriginOfMandatory());
+ }
+ } else {
+ /* node is introduced by this update layer */
+ resultNode = this;
+ aResultNode.addChildNode(resultNode);
+ if (!aIsParentUpdateLayer) {
+ resultNode.setAddedAtTopLayer();
+ }
+ }
+ resultNode.setPath(aUpdateNodePath);
+ if (mAllChildrenNames != null) {
+ int size = mAllChildrenNames.size();
+ for (int i = 0; i < size; i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ String updateNodePath = null;
+ PolicyNodeImpl updateNode = null;
+ if (mChildNodeTable != null) {
+ updateNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (updateNode != null) {
+ updateNodePath = appendToPath(aUpdateNodePath, updateNode.getName());
+ updateNode.processReadOperation(resultNode,
+ aUpdateNodeKey, updateNodePath, aIsParentUpdateLayer);
+ }
+ }
+ if (updateNode == null && mPropertyTable != null) {
+ PropertyImpl property = (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ updateNodePath = appendToPath(aUpdateNodePath, property.getName());
+ property.processReadOperation(resultNode,
+ aUpdateNodeKey, updateNodePath,
+ aIsParentUpdateLayer);
+ }
+ }
+ }
+ }
+ /* Check if this update node is finalized. If it is, and this
+ is a parent update layer being processed, then set the readonly
+ attribute to true for this node and its children. If it is
+ finalized and this is a source layer, or is not a parent layer,
+ then set the finalized attribute to true */
+ if (isProtected()) {
+ try {
+ resultNode.checkIfNodeOrChildrenReadOnly();
+ resultNode.setFinalized(true, resultNode.getAbsolutePath(),
+ getOriginOfProtection());
+ if (aIsParentUpdateLayer) {
+ resultNode.setReadOnly();
+ }
+ } catch (SPIException ignore) {}
+ }
+ }
+
+ /**
+ * Carries out the removal operation specified in
+ * this update node. For a read merge this operation
+ * results in the deletion of specified subnodes of a
+ * set.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void readRemoveNode(PolicyNodeImpl aResultNode,
+ String aUpdateNodePath, boolean aIsParentUpdateLayer)
+ throws SPIException {
+ PolicyNodeImpl childNode =
+ aResultNode.getChild(getName());
+ if (childNode != null) {
+ if (!childNode.isMandatory()) {
+ /* need to keep track of nodes deleted by the final
+ update layer, in order to include them in the update
+ layer written by updateComponent */
+ if (!aIsParentUpdateLayer) {
+ /* set the operation attribute to "remove" */
+ childNode.setOperationType(OperationType.OP_REMOVE);
+ aResultNode.addRemovedChild(childNode);
+ }
+ aResultNode.deleteChildNode(childNode.getName());
+ }
+ }
+ }
+
+
+ /**
+ * Carries out the replacement operation specified in
+ * this update node. This operation can only be applied
+ * to dynamic elements. The replace operation can either
+ * insert a new node or replace a node that already exists.
+ * The corresponding node from the source layer is ignored.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void readReplaceNode(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException {
+
+ /* if the corresponding node exists in the source
+ layer, and it is mandatory then the replace operation
+ is ignored */
+ PolicyNodeImpl sourceLayerNode =
+ aResultNode.getChild(getName());
+ if (sourceLayerNode != null &&
+ sourceLayerNode.isMandatory()) {
+ return;
+ }
+ String path = appendToPath(aResultNode.getAbsolutePath(), getName());
+ setSettingsForAddedNode(path, getOrigin(), aIsParentUpdateLayer);
+
+ /* Check if this update node is finalized. If it is, and this
+ is a parent layer being processed, then set the readonly
+ attribute to true for this node and its children. If it is
+ finalized and this is a source layer, or if this is not
+ a parent layer, then set the finalized attribute to true */
+ if (isProtected()) {
+ setFinalized(true, getAbsolutePath(),getOriginOfProtection());
+ if (aIsParentUpdateLayer) {
+ setReadOnly();
+ }
+ }
+ aResultNode.addChildNode(this);
+ }
+
+ /**
+ * Removes a child node.
+ *
+ * @param aNodeName name of node to be removed
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public void removeNode(String aNodeName)
+ throws SPIException {
+ if (aNodeName == null) { return; }
+ PolicyNodeImpl childNode = getChildNode(aNodeName);
+ removeNode(childNode);
+ }
+
+ /**
+ * Removes a child node.
+ *
+ * @param aNode node to be removed
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public void removeNode(PolicyNodeImpl aNode)
+ throws SPIException {
+ if (aNode == null) { return; }
+ /* if the set is marked readonly, then the
+ operation cannot proceed */
+ checkIfReadOnly();
+ /* if the node or its children are readonly
+ or mandatory then the node cannot be removed */
+ aNode.checkIfNodeOrChildrenReadOnlyOrMandatory();
+ /* If the node was added at a parent layer, then
+ need to write this node to the update layer
+ with "op=remove" attribute set */
+ if (!aNode.isAddedAtTopLayer()) {
+ /* set the operation attribute to "remove" */
+ aNode.setOperationType(OperationType.OP_REMOVE);
+ addRemovedChild((PolicyNodeImpl)aNode);
+ }
+ deleteChildNode(aNode.getName());
+ mHasBeenModified = true;
+ }
+
+ /**
+ * Removes a property.
+ *
+ * @param aPropertyName name of property to be removed
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public void removeProperty(String aPropertyName)
+ throws SPIException {
+ if (aPropertyName == null) { return; }
+ PropertyImpl property = (PropertyImpl)getProperty(aPropertyName);
+ removeProperty(property);
+ }
+
+ /**
+ * Removes a property.
+ *
+ * @param aProperty property to be removed
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public void removeProperty(PropertyImpl aProperty)
+ throws SPIException {
+ if (aProperty == null) { return; }
+ /* if the set is marked readonly, then the
+ operation cannot proceed */
+ checkIfReadOnly();
+ /* if the node or its children are readonly
+ or mandatory then the node cannot be removed */
+ aProperty.checkIfReadOnly();
+ aProperty.checkIfMandatory();
+ /* If the node was added at a parent layer, then
+ need to write this node to the update layer
+ with "op=remove" attribute set */
+ if (!aProperty.isAddedAtTopLayer()) {
+ /* set the operation attribute to "remove" */
+ aProperty.setOperationType(OperationType.OP_REMOVE);
+ addRemovedChild(aProperty);
+ }
+ deleteProperty(aProperty);
+ mHasBeenModified = true;
+ }
+
+ /**
+ * Sets the default node, that is the node as it was in the
+ * default layer.
+ *
+ * @param aDefaultNode the default node
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public void setDefaultNode(ReadWritePolicyNodeImpl aDefaultNode)
+ throws SPIException {
+ mDefaultNode = aDefaultNode;
+ }
+
+ /**
+ * Sets the node and its children to default.
+ *
+ * @param aDefaultNode the default for the node on which
+ * the setDefault() method was called
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private void setNodeAndChildrenToDefault(
+ ReadWritePolicyNodeImpl aDefaultNode) throws SPIException {
+ if (mChildNodeTable != null) {
+ Enumeration childNodes = mChildNodeTable.elements();
+ while (childNodes.hasMoreElements()) {
+ ReadWritePolicyNodeImpl childNode =
+ (ReadWritePolicyNodeImpl)childNodes.nextElement();
+ ReadWritePolicyNodeImpl defaultChildNode =
+ childNode.mDefaultNode;
+ if (defaultChildNode != null) {
+ childNode.setNodeAndChildrenToDefault(
+ defaultChildNode);
+ aDefaultNode.addChildNode(defaultChildNode);
+ }
+ }
+ }
+ if (mPropertyTable != null) {
+ Enumeration properties = mPropertyTable.elements();
+ while (properties.hasMoreElements()) {
+ ReadWritePropertyImpl property =
+ (ReadWritePropertyImpl)properties.nextElement();
+ ReadWritePropertyImpl defaultProperty =
+ property.getDefaultProperty();
+ if (defaultProperty != null) {
+ aDefaultNode.addProperty(defaultProperty);
+ }
+ }
+ }
+ if (mRemovedChildren != null) {
+ for (int i = 0; i < mRemovedChildren.size(); i++) {
+ Object removedChild = mRemovedChildren.get(i);
+ if (removedChild instanceof PolicyNodeImpl) {
+ PolicyNodeImpl defaultRemovedChildNode =
+ ((ReadWritePolicyNodeImpl)removedChild).getDefaultNode();
+ if (defaultRemovedChildNode != null) {
+ aDefaultNode.addChildNode(defaultRemovedChildNode);
+ }
+ } else {
+ ReadWritePropertyImpl defaultRemovedProperty =
+ ((ReadWritePropertyImpl)removedChild).getDefaultProperty();
+ if (defaultRemovedProperty != null) {
+ aDefaultNode.addProperty(defaultRemovedProperty);
+ }
+ }
+ }
+ }
+ aDefaultNode.setDefaultNode((ReadWritePolicyNodeImpl)aDefaultNode.shallowCopy());
+ }
+
+ /**
+ * Sets the value of the finalized property of the node,
+ * and its children.
+ *
+ * @param aIsProtected <code>true</code> if the node
+ * is finalized, <code>false</code>
+ * otherwise
+ * @throws <code>SPIException</code> if operation
+ * is not permitted
+ */
+ public void setProtected(boolean aIsProtected)
+ throws SPIException {
+ setProtected(aIsProtected, getAbsolutePath(),
+ mPolicyTree.getPolicy());
+ }
+
+ /**
+ * Sets the value of the finalized property of the node,
+ * and its children.
+ *
+ * @param aIsProtected <code>true</code> if the node
+ * is finalized, <code>false</code>
+ * otherwise
+ * @param aNameOfElementWhereProtectionSet name of the node where
+ * the flag was set
+ * (null if aIsProtected is
+ * <code>false</code>
+ * @param aOriginOfProtection layer where the flag was set
+ * (null if aIsProtected is
+ * <code>false</code>
+ * @throws <code>SPIException</code> if operation
+ * is not permitted
+ */
+ public void setProtected(boolean aIsProtected,
+ String aNameOfElementWhereProtectionSet,
+ Policy aOriginOfProtection)
+ throws SPIException {
+ checkIfNodeOrChildrenReadOnly();
+ mIsProtected = aIsProtected ;
+ mNameOfElementWhereProtectionSet = aNameOfElementWhereProtectionSet;
+ mOriginOfProtection = aOriginOfProtection;
+ mHasBeenModified = true;
+ if (mAllChildrenNames != null) {
+ for (int i = 0; i < mAllChildrenNames.size(); i++) {
+ String name = (String)mAllChildrenNames.get(i);
+ PolicyNodeImpl childNode = null;
+ if (mChildNodeTable != null) {
+ childNode =
+ (PolicyNodeImpl)mChildNodeTable.get(name);
+ if (childNode != null) {
+ childNode.setFinalized(aIsProtected,
+ aNameOfElementWhereProtectionSet,
+ aOriginOfProtection);
+ }
+ }
+ if (childNode == null && mPropertyTable != null) {
+ PropertyImpl property =
+ (PropertyImpl)mPropertyTable.get(name);
+ if (property != null) {
+ property.setFinalized(aIsProtected,
+ aNameOfElementWhereProtectionSet,
+ aOriginOfProtection);
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Sets the node name.
+ */
+ public void setName(String aName) {
+ mHasBeenModified = true;
+ mName = aName;
+ }
+
+ /**
+ * Returns a shallow copy of the node (excludes child nodes).
+ *
+ * @return copy of the node
+ * @throws <code>SPIException</code> if cannot
+ * create copy
+ */
+ public ConfigElementImpl shallowCopy() throws SPIException {
+ ConfigElementImpl retNode = super.shallowCopy();
+ ((ReadWritePolicyNodeImpl)retNode).mDefaultNode = mDefaultNode;
+ return retNode;
+ }
+
+ /**
+ * Carries out the update merge modification operation specified in
+ * this result node.
+ *
+ * @param aOutputNode the equivalent node for the new
+ * update layer
+ * @param aLayer layer to update
+ * @param aUpdateNodePath the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node
+ * is required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean updateModifyNode(PolicyNodeImpl aOutputNode,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException{
+ boolean update = false;
+ /* should be included if the protect function was
+ applied directly to this node. */
+ if (mIsProtected) {
+ if (getParent() == null || !
+ ((PolicyNodeImpl)getParent()).isProtected()) {
+ update = true;
+ }
+ } else if (mIsMandatory &&
+ aLayer.equals(mOriginOfMandatory) ) {
+ update = true;
+ }
+
+ /* if this layer removed any inherited dynamic members,
+ then add these nodes (with op=remove) to the
+ output child node */
+ if (mRemovedChildren != null) {
+ for (int i = 0; i < mRemovedChildren.size(); i ++) {
+ Object removedChild =
+ mRemovedChildren.get(i);
+ if (removedChild != null) {
+ if (removedChild instanceof PolicyNodeImpl) {
+ aOutputNode.addChildNode(
+ (PolicyNodeImpl)((PolicyNodeImpl)removedChild).shallowCopy());
+ update = true;
+ } else if (removedChild instanceof PropertyImpl) {
+ aOutputNode.addProperty(
+ (PropertyImpl)((PropertyImpl)removedChild).shallowCopy());
+ update = true;
+ }
+ }
+ }
+ }
+ boolean childrenUpdate =
+ processUpdateNodeChildren(aOutputNode,
+ aLayer, aUpdateNodePath);
+ return update || childrenUpdate;
+ }
+
+ /**
+ * Carries out the update merge remove operation specified in
+ * this result node.
+ *
+ * @param aOutputNode the equivalent node for the new
+ * update layer
+ * @param aLayer layer to be updated
+ * @param aUpdateNodePat the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean updateRemoveNode(PolicyNodeImpl aOutputNode,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ PolicyNodeImpl parentNode = (PolicyNodeImpl)getParent();
+ if (!mIsAddedAtTopLayer) {
+ parentNode.addRemovedChild(this);
+ }
+ // delete the node from the cached node
+ parentNode.deleteChildNode(mName);
+ return mIsAddedAtTopLayer ? false : true;
+ }
+
+
+ /**
+ * Carries out the update merge replacement operation specified in
+ * this result node.
+ *
+ * @param aOutputNode the equivalent node for the new
+ * update layer
+ * @param aLayer layer to be updated
+ * @param aUpdateNodePath the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node
+ * is required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean updateReplaceNode(PolicyNodeImpl aOutputNode,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ boolean update = false;
+ boolean childrenUpdate = false;
+ if (mIsAddedAtTopLayer) {
+ update = true;
+ } else if (mIsProtected) {
+ if (getParent() == null ||
+ !((PolicyNodeImpl)getParent()).isProtected()) {
+ /* should be included if the protect or setMandatory
+ function was applied directly to this node. */
+ update = true;
+ }
+ } else if (mIsMandatory &&
+ mOriginOfMandatory.equals(aLayer)) {
+ update = true;
+ }
+ /* if this layer removed any inherited set members,
+ then add these nodes (with op=remove) to the
+ output child node */
+ if (mRemovedChildren != null) {
+ for (int i = 0; i < mRemovedChildren.size(); i++) {
+ Object removedChild =
+ mRemovedChildren.get(i);
+ if (removedChild != null) {
+ if (removedChild instanceof PolicyNodeImpl) {
+ aOutputNode.addChildNode(
+ (PolicyNodeImpl)((PolicyNodeImpl)removedChild).shallowCopy());
+ update = true;
+ } else if (removedChild instanceof PropertyImpl) {
+ aOutputNode.addProperty(
+ (PropertyImpl)((PropertyImpl)removedChild).shallowCopy());
+ update = true;
+ }
+ }
+ }
+ }
+ childrenUpdate = processUpdateNodeChildren(
+ aOutputNode, aLayer, aUpdateNodePath);
+ return update || childrenUpdate;
+ }
+
+ /**
+ * Carries out the update merge reset operation specified in
+ * this result node.
+ *
+ * @param aOutputNode the equivalent node for the new
+ * update layer
+ * @param aLayer layer to be updated
+ * @param aUpdateNodePath the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean updateResetNode(PolicyNodeImpl aOutputNode,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ /* a node with the operation attribute reset will
+ have been "rolled back" to the default node. However,
+ it may have nested operations */
+ boolean update = false;
+ if (mIsProtected) {
+ if (getParent() == null ||
+ !((PolicyNodeImpl)getParent()).isProtected()) {
+ /* should be included if the protect or setMandatory
+ function was applied directly to this node. */
+ update = true;
+ }
+ } else if (mIsMandatory &&
+ mOriginOfMandatory.equals(aLayer)) {
+ update = true;
+ }
+ boolean childrenUpdate =
+ processUpdateNodeChildren(aOutputNode, aLayer,
+ aUpdateNodePath);
+ if (!update && !childrenUpdate) {
+ return false;
+ } else {
+ /* Change the operation attribute to "modify" */
+ aOutputNode.setOperationType(OperationType.OP_MODIFY);
+ return true;
+ }
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyException.java b/src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyException.java
new file mode 100644
index 0000000..fbd1a1b
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyException.java
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree.property;
+
+public class InvalidPropertyException extends PropertyException {
+
+ private static final String INVALID_PROPERTY_KEY =
+ "error.spi.policytree.property.invalid";
+ public static final String INVALID_VALUE_KEY =
+ "error.spi.policytree.property.value.invalid";
+ public static final String NOTNIL_PROPERTY_KEY =
+ "error.spi.policytree.property.nonil";
+
+ public InvalidPropertyException () {
+ super();
+ mMessageKey = INVALID_PROPERTY_KEY;
+ }
+
+ public InvalidPropertyException (String messageKey) {
+ super();
+ mMessageKey = messageKey;
+ }
+
+ public InvalidPropertyException (String messageKey, String name) {
+ super();
+ mMessageKey = messageKey;
+ mMessageParams = new Object[]{name};
+ }
+
+ public InvalidPropertyException (String messageKey,
+ Throwable cause) {
+ super(cause);
+ mMessageKey = messageKey;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyNameException.java b/src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyNameException.java
new file mode 100644
index 0000000..0014aa2
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/property/InvalidPropertyNameException.java
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree.property;
+
+public class InvalidPropertyNameException extends PropertyException {
+
+ private static final String INVALID_NAME_PROPERTY_KEY =
+ "error.spi.policytree.property.name.invalid";
+
+ protected String mName;
+
+ public InvalidPropertyNameException () {
+ super();
+ }
+
+ public InvalidPropertyNameException (String name) {
+ super();
+ mName = name;
+ mMessageKey = INVALID_NAME_PROPERTY_KEY;
+ mMessageParams = new Object[]{mName};
+ }
+
+ public String getName () { return mName; }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/property/MergedProperty.java b/src/com/sun/apoc/spi/cfgtree/property/MergedProperty.java
new file mode 100644
index 0000000..edd976d
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/property/MergedProperty.java
@@ -0,0 +1,73 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.property;
+
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Interface for a merged policy node.
+ *
+ */
+public interface MergedProperty extends Property {
+
+ /**
+ * Returns the <code>Profile</code> object where this node
+ * originated.
+ *
+ * @return <code>Profile</code> where this merged node
+ * originated
+ */
+ public Policy getOrigin() ;
+
+ /**
+ * Returns the <code>Profile</code> object where the
+ * protected attribute originated.
+ *
+ * @return <code>Profile</code> where the protected
+ * attribute originated
+ */
+ public Policy getOriginOfProtection() ;
+
+ /**
+ * Returns the <code>Profile</code> object where the
+ * value originated.
+ *
+ * @return <code>Profile</code> where the value
+ * originated
+ */
+ public Policy getOriginOfValue() ;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/property/Property.java b/src/com/sun/apoc/spi/cfgtree/property/Property.java
new file mode 100644
index 0000000..97c14e1
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/property/Property.java
@@ -0,0 +1,279 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.property;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.DataType;
+import com.sun.apoc.spi.cfgtree.ProtectedElement;
+
+/**
+ * Interface for a property.
+ *
+ */
+public interface Property extends ProtectedElement{
+
+ /**
+ * Returns the value as a string.
+ *
+ * @return the value as a string
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getValue() throws SPIException;
+
+ /**
+ * Returns the data type.
+ *
+ * @return the data type
+ */
+ public DataType getDataType() ;
+
+ /**
+ * Returns a boolean indicating if the property is nil.
+ *
+ * @return <code>true</code> if nil, otherwise
+ * <code>false</code>
+ */
+ public boolean isNil() ;
+
+ /**
+ * Returns the value as an int.
+ *
+ * @return the value as an int
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public int getInt() throws SPIException;
+
+ /**
+ * Returns the value as a double.
+ *
+ * @return the value as a double
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public double getDouble() throws SPIException;
+
+ /**
+ * Returns the value as a short.
+ *
+ * @return the value as a short
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public short getShort() throws SPIException;
+
+ /**
+ * Returns the value as a long.
+ *
+ * @return the value as a long
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public long getLong() throws SPIException;
+
+ /**
+ * Returns the value as a boolean.
+ *
+ * @return the value as a boolean
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean getBoolean() throws SPIException;
+
+ /**
+ * Returns the value as an array of ints.
+ *
+ * @return the value as an array of ints
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public int[] getIntList() throws SPIException;
+
+ /**
+ * Returns the value as an array of doubles.
+ *
+ * @return the value as an array of doubles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public double[] getDoubleList() throws SPIException;
+
+ /**
+ * Returns the value as an array of shorts.
+ *
+ * @return the value as an array of shorts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public short[] getShortList() throws SPIException;
+
+ /**
+ * Returns the value as an array of longs.
+ *
+ * @return the value as an array of longs
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public long[] getLongList() throws SPIException;
+
+ /**
+ * Returns the value as an array of booleans.
+ *
+ * @return the value as an array of booleans
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean[] getBooleanList() throws SPIException;
+
+ /**
+ * Returns the separator.
+ *
+ * @return the separator
+ */
+ public String getSeparator() ;
+
+ /**
+ * Sets the value.
+ *
+ * @param aValue the value
+ * @param aDataType the type of the data
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void put(String aValue, DataType aDataType) throws SPIException;
+
+ /**
+ * Sets the string value.
+ *
+ * @param aValue the string value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putString(String aValue) throws SPIException;
+
+ /**
+ * Sets the int value.
+ *
+ * @param aValue the int value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putInt(int aValue) throws SPIException;
+
+ /**
+ * Sets the double value.
+ *
+ * @param aValue the double value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putDouble(double aValue) throws SPIException;
+
+ /**
+ * Sets the short value.
+ *
+ * @param aValue the short value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putShort(short aValue) throws SPIException;
+
+ /**
+ * Sets the long value.
+ *
+ * @param aValue the long value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putLong(long aValue) throws SPIException;
+
+ /**
+ * Sets the boolean value.
+ *
+ * @param aValue the boolean value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putBoolean(boolean aValue) throws SPIException;
+
+ /**
+ * Sets the string list values.
+ *
+ * @param aValues the list of string values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putStringList(String[] aValues) throws SPIException;
+
+ /**
+ * Sets the hexbinary list values.
+ *
+ * @param aValues the list of hexbinary values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putHexBinaryList(String[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of int value.
+ *
+ * @param aValues the list of int values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putIntList(int[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of double values.
+ *
+ * @param aValues the list of double values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putDoubleList(double[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of short values.
+ *
+ * @param aValues the list of short values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putShortList(short[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of long values.
+ *
+ * @param aValues the list of long values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void putLongList(long []aValues) throws SPIException;
+
+ /**
+ * Sets the list of boolean values.
+ *
+ * @param aValues the list of boolean values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putBooleanList(boolean[] aValues) throws SPIException;
+
+
+ /**
+ * Sets the separator.
+ *
+ * @param aSeparator the separator
+ */
+ public void setSeparator(String aSeparator) ;
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/property/PropertyException.java b/src/com/sun/apoc/spi/cfgtree/property/PropertyException.java
new file mode 100644
index 0000000..9c83d54
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/property/PropertyException.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.cfgtree.property;
+
+import com.sun.apoc.spi.cfgtree.PolicyTreeException;
+
+public class PropertyException extends PolicyTreeException {
+
+ public PropertyException () {
+ super();
+ }
+
+ public PropertyException (Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/property/PropertyImpl.java b/src/com/sun/apoc/spi/cfgtree/property/PropertyImpl.java
new file mode 100644
index 0000000..2f3ce34
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/property/PropertyImpl.java
@@ -0,0 +1,1192 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.property;
+
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.ConfigElementImpl;
+import com.sun.apoc.spi.cfgtree.DataType;
+import com.sun.apoc.spi.cfgtree.InvalidDataTypeException;
+import com.sun.apoc.spi.cfgtree.NodeKey;
+import com.sun.apoc.spi.cfgtree.NodeParsing;
+import com.sun.apoc.spi.cfgtree.NodeValueImpl;
+import com.sun.apoc.spi.cfgtree.OperationType;
+import com.sun.apoc.spi.cfgtree.PolicyTree;
+import com.sun.apoc.spi.cfgtree.ProtectedElementImpl;
+import com.sun.apoc.spi.cfgtree.XMLStreamable;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNodeImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Abstract class for a property.
+ *
+ */
+public abstract class PropertyImpl extends ProtectedElementImpl implements Property, MergedProperty, XMLStreamable {
+
+ /** Value type */
+ public DataType mDataType = DataType.UNKNOWN ;
+ /** boolean indicating if property is localized */
+ public boolean mLocalized = false;
+ /** boolean indicating if property may assume value nil */
+ public boolean mNillable = true;
+ /** locale */
+ public String mRequiredLocale = PolicyTree.DEFAULT_LOCALE_NAME;
+ /** the separator used */
+ public String mSeparator = NodeParsing.WHITESPACE;
+ /** the layer where the property originated */
+ protected Policy mOriginLayer;
+ /** the name of the element, including path, where the finalized
+ attribute was set to true */
+ protected String mNameOfElementWhereProtectionSet;
+ /** the layer where the finalized attribute was set to true */
+ protected Policy mOriginOfProtection;
+ /** Node value table */
+ public Hashtable mValues ;
+
+
+ /**
+ * Utility function for creating a copy of a table of
+ * <code>NodeValueImpls</code>.
+ *
+ * @param aOriginalTable the table to be copied
+ * @param aPropertyImpl the property to which the new table belongs
+ * @return new table
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public Hashtable copyNodeValueImplTable(Hashtable aOriginalTable,
+ PropertyImpl aPropertyImpl) throws SPIException {
+ Hashtable newTable = new Hashtable();
+ Enumeration keys = aOriginalTable.keys();
+ if (keys != null) {
+ while (keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ NodeValueImpl origNodeValueImpl = (NodeValueImpl)aOriginalTable.get(key);
+ if (origNodeValueImpl != null) {
+ NodeValueImpl newNodeValueImpl = origNodeValueImpl.copyNodeValueImpl();
+ newNodeValueImpl.setPropertyImpl(aPropertyImpl);
+ newTable.put(key, newNodeValueImpl);
+ }
+ }
+ }
+ return newTable;
+ }
+
+ /**
+ * Creates a new default <code>NodeValueImpl</code>.
+ *
+ * @return the new <code>NodeValueImpl</code>
+ */
+ public NodeValueImpl createDefaultNodeValueImpl() {
+ NodeValueImpl defaultValue = new NodeValueImpl();
+ defaultValue.setPropertyImpl(this);
+ defaultValue.setNilAttribute(true);
+ defaultValue.setDataType(mDataType);
+ return defaultValue;
+ }
+
+ /**
+ * Expands the base source layer node.
+ *
+ * @param aPath the name of this property, including path
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void expand(String aPath, boolean aIsParentUpdateLayer)
+ throws SPIException {
+ mPath = aPath;
+ if (isProtected()) {
+ if (getParent() == null ||
+ !getParent().isProtected()){
+ setFinalized(true, getAbsolutePath(),
+ getOriginOfProtection());
+ }
+ if (aIsParentUpdateLayer) {
+ setReadOnly();
+ }
+ }
+ }
+
+ /**
+ * Returns a string representing the attributes of
+ * the node.
+ *
+ * @param aFormat format
+ * @return attribute string
+ */
+ public String getAttributes(int aFormat) {
+ StringBuffer retCode = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ retCode.append(NodeParsing.NAME_ATTR).append(
+ "=\"").append(getName()).append("\"") ;
+ String operationProp =
+ OperationType.getString(getOperationType());
+ if (operationProp != null &&
+ operationProp.equals(OperationType.REPLACE_STR)) {
+ retCode.append(" ").append(
+ NodeParsing.OPERATION_ATTR).append("=\"").append(
+ operationProp).append("\"");
+ }
+ switch (aFormat) {
+ case UPDATE_SCHEMA:
+ case POLICY_SCHEMA:
+ if (isProtected()) {
+ if (getParent() == null ||
+ !getParent().isProtected()) {
+ retCode.append(" ").append(
+ NodeParsing.FINALIZED_ATTR).append(
+ "=\"true\"") ;
+ }
+ }
+ if (isLocalized()) {
+ retCode.append(" ").append(
+ NodeParsing.LOCALIZED_ATTR).append("=\"true\"") ;
+ }
+ if (!mNillable) {
+ retCode.append(" ").append(
+ NodeParsing.NILLABLE_ATTR).append("=\"false\"") ;
+ }
+ if (mDataType != DataType.UNKNOWN) {
+ retCode.append(" ").append(
+ NodeParsing.TYPE_ATTR).append("=\"").append(
+ mDataType.getStringValue()).append("\"");
+ }
+ break;
+ case MERGED_SCHEMA:
+ if (isReadOnly()) {
+ retCode.append(" ").append(
+ NodeParsing.READONLY_ATTR).append("=\"true\"") ;
+ } else if (isProtected()) {
+ retCode.append(" ").append(
+ NodeParsing.FINALIZED_ATTR).append("=\"true\"") ;
+ }
+ if (isLocalized()) {
+ retCode.append(" ").append(
+ NodeParsing.LOCALIZED_ATTR).append("=\"true\"") ;
+ }
+ if (!isNillable()) {
+ retCode.append(" ").append(
+ NodeParsing.NILLABLE_ATTR).append("=\"false\"") ;
+ }
+ if (mDataType != DataType.UNKNOWN) {
+ retCode.append(" ").append(
+ NodeParsing.TYPE_ATTR).append("=\"").append(
+ mDataType.getStringValue()).append("\"");
+ }
+ break;
+ };
+ return retCode.toString();
+ }
+
+
+
+ /**
+ * Returns the data type.
+ *
+ * @return the data type
+ */
+ public DataType getDataType() {
+ return mDataType;
+ }
+
+ /**
+ * Gets the name of the element (including path) where the finalized
+ * attribute was set.
+ *
+ * @return name of the element, including path
+ */
+ public String getNameOfElementWhereProtectionSet() {
+ return mNameOfElementWhereProtectionSet;
+ }
+
+ /**
+ * Returns the node value for the locale as
+ * as specified by the policy tree. If there is
+ * not a node value for this locale, the function
+ * will return, in order of preference:
+ * 1) the node value containing the default data;
+ * or 2) the node value for "en-US";
+ * or 3) another localized node value;
+ * or 4) a newly created default node value.
+ *
+ * @return <code>NodeValue</code>
+ */
+ public NodeValueImpl getNodeValue() {
+ NodeValueImpl nodeValue = null;
+ if (mValues != null) {
+ if (mLocalized) {
+ nodeValue = (NodeValueImpl)mValues.get(mRequiredLocale);
+ } else {
+ nodeValue =
+ (NodeValueImpl)mValues.get(PolicyTree.DEFAULT_LOCALE_NAME);
+ }
+ /* if don't have the required NodeValueImpl, then provide
+ a default one */
+ if (nodeValue == null && mLocalized) {
+ nodeValue = (NodeValueImpl)mValues.get(PolicyTree.DEFAULT_LOCALE_NAME);
+ if (nodeValue != null) {
+ nodeValue = nodeValue.copyNodeValueImpl();
+ }
+ }
+ if (nodeValue == null && mLocalized) {
+ nodeValue = (NodeValueImpl)mValues.get("en-US");
+ if (nodeValue != null) {
+ nodeValue = nodeValue.copyNodeValueImpl();
+ }
+ }
+ if (nodeValue == null && mLocalized) {
+ Enumeration keys = mValues.keys();
+ if (keys != null) {
+ while(keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ if (key != null) {
+ nodeValue =
+ (NodeValueImpl)mValues.get(key);
+ if (nodeValue != null) {
+ nodeValue = nodeValue.copyNodeValueImpl();
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (nodeValue == null) {
+ /* create a default NodeValue */
+ nodeValue = createDefaultNodeValueImpl();
+ }
+ return nodeValue;
+ }
+
+ /**
+ * Returns the node value for the specified locale,
+ * or null if it does not exist.
+ *
+ * @param aLocale the required locale
+ * @return <code>NodeValueImpl</code> for
+ * the specified locale, or null
+ * if it does not exist
+ */
+ public NodeValueImpl getNodeValue(String aLocale) {
+ if (mValues == null) { return null; }
+ return (NodeValueImpl)mValues.get(aLocale);
+ }
+
+ /**
+ * Returns the profile where the element
+ * originated.
+ *
+ * @return the profile where the element originated
+ */
+ public Policy getOrigin() { return mOriginLayer; }
+
+ /**
+ * Gets the Policy where the finalized attribute
+ * was set.
+ *
+ * @return the Policy where the attribute was set
+ */
+ public Policy getOriginOfProtection() {
+ return mOriginOfProtection;
+ }
+
+ /**
+ * Returns the <code>Policy</code> object where the
+ * value originated.
+ *
+ * @return <code>Policy</code> where the value
+ * originated
+ */
+ public Policy getOriginOfValue() {
+ return getNodeValue().getOrigin();
+ }
+
+
+ /**
+ * Returns the required locale.
+ *
+ * @return the locale specified by the policy tree.
+ * If the property is not localized, then null
+ * is returned.
+ */
+ public String getRequiredLocale() {
+ // If the property is not localized to begin with,
+ // we don't care about the locale.
+ return mLocalized ? mRequiredLocale : null ;
+ }
+
+ /**
+ * Returns the separator.
+ *
+ * @return the separator
+ */
+ public String getSeparator() {
+ return mSeparator;
+ }
+
+ /**
+ * Returns the value as a string.
+ *
+ * @return the value as a string
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getValue() throws SPIException {
+ String retCode = getNodeValue().getContents();
+ return retCode;
+ }
+
+ /**
+ * Returns the values hashtable.
+ *
+ * @return values hashtable
+ */
+ public Hashtable getValues() {
+ return mValues;
+ }
+
+
+ /**
+ * Returns the string value.
+ *
+ * @return the string value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public String getStringValue() throws SPIException {
+ if (mDataType != DataType.STRING) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ return getNodeValue().getContents();
+ }
+
+ /**
+ * Returns the hexBinary value as a string.
+ *
+ * @return the hexBinary value as a string
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public String getHexBinary() throws SPIException {
+ if (mDataType != DataType.HEXBIN) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ return getNodeValue().getContents();
+ }
+
+ /**
+ * Returns the value as an int.
+ *
+ * @return the value as an int
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public int getInt() throws SPIException {
+ if (mDataType != DataType.INT) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String value = getNodeValue().getContents();
+ if (value == null) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ int retCode = 0;
+ try {
+ retCode = Integer.parseInt(value);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ return retCode;
+ }
+
+
+ /**
+ * Returns the value as a double.
+ *
+ * @return the value as a double
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public double getDouble() throws SPIException {
+ if (mDataType != DataType.DOUBLE) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String value = getNodeValue().getContents();
+ if (value == null) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ double retCode = 0;
+ try {
+ retCode = Double.parseDouble(value);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the value as a short.
+ *
+ * @return the value as a short
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public short getShort() throws SPIException {
+ if (mDataType != DataType.SHORT) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String value = getNodeValue().getContents();
+ if (value == null) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ short retCode = 0;
+ try {
+ retCode = Short.parseShort(value);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the value as a long.
+ *
+ * @return the value as a long
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public long getLong() throws SPIException{
+ if (mDataType != DataType.LONG) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String value = getNodeValue().getContents();
+ if (value == null) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ long retCode = 0;
+ try {
+ retCode = Long.parseLong(value);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the value as a boolean.
+ *
+ * @return the value as a boolean
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public boolean getBoolean() throws SPIException {
+ if (mDataType != DataType.BOOLEAN) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String value = getNodeValue().getContents();
+ if (value == null) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ boolean retCode = false;
+ if (value.equalsIgnoreCase("true")) {
+ retCode = true;
+ } else if (!value.equalsIgnoreCase("false")) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the values as a string array.
+ *
+ * @return the values as a string array
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public String[] getHexBinaryList() throws SPIException {
+ if (mDataType != DataType.STRING_LIST) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ return getNodeValue().getValueArray();
+ }
+
+ /**
+ * Returns the values as an array of ints.
+ *
+ * @return the value as an array of ints
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidElementException if invalid value
+ */
+ public int[] getIntList() throws SPIException {
+ if (mDataType != DataType.INT_LIST) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String[] values = getNodeValue().getValueArray();
+ if (values.length == 0) { return new int[0]; }
+ int []retCode = new int[values.length];
+ for (int i = 0; i < values.length; ++i) {
+ try {
+ retCode[i] = Integer.parseInt(values[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the value as an array of doubles.
+ *
+ * @return the value as an array of doubles
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidElementException if invalid value
+ */
+ public double[] getDoubleList() throws SPIException {
+ if (mDataType != DataType.DOUBLE_LIST) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String[] values = getNodeValue().getValueArray();
+ if (values.length == 0) { return new double[0]; }
+ double []retCode = new double[values.length];
+ for (int i = 0; i < values.length; ++i) {
+ try {
+ retCode[i] = Double.parseDouble(values[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the value as an array of shorts.
+ *
+ * @return the value as an array of shorts
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidElementException if invalid value
+ */
+ public short[] getShortList() throws SPIException {
+ if (mDataType != DataType.SHORT_LIST) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String[] values = getNodeValue().getValueArray();
+ if (values.length == 0) { return new short[0]; }
+ short []retCode = new short[values.length];
+ for (int i = 0; i < values.length; ++i) {
+ try {
+ retCode[i] = Short.parseShort(values[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the value as an array of longs.
+ *
+ * @return the value as an array of longs
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidElementException if invalid value
+ */
+ public long[] getLongList() throws SPIException {
+ if (mDataType != DataType.LONG_LIST) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String[] values = getNodeValue().getValueArray();
+ if (values.length == 0) { return new long[0]; }
+ long []retCode = new long[values.length];
+ for (int i = 0; i < values.length; ++i) {
+ try {
+ retCode[i] = Long.parseLong(values[i]);
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY,
+ nfe);
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the value as an array of booleans.
+ *
+ * @return the value as an array of booleans
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public boolean[] getBooleanList() throws SPIException {
+ if (mDataType != DataType.BOOLEAN_LIST) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ String[] values = getNodeValue().getValueArray();
+ if (values.length == 0) { return new boolean[0]; }
+ boolean []retCode = new boolean[values.length];
+ for (int i = 0; i < values.length; ++i) {
+ if (values[i].equalsIgnoreCase("true")) {
+ retCode[i] = true;
+ } else if (values[i].equalsIgnoreCase("false")) {
+ retCode[i] = false;
+ } else {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns the setting of the localized flag.
+ *
+ * @return <code>true</code> if property is
+ * localized, otherwise <code>false</code>
+ */
+ public boolean isLocalized() {
+ return mLocalized;
+ }
+
+
+ /**
+ * Returns a boolean indicating if the property is nil.
+ *
+ * @return <code>true</code> if nil, otherwise
+ * <code>false</code>
+ */
+ public boolean isNil() {
+ return getNodeValue().hasNilAttribute();
+ }
+
+ /**
+ * Returns the setting of the nillable flag, indicating
+ * whether or not the property may assume the value nil.
+ *
+ * @return <code>true</code> if node is
+ * nillable, otherwise <code>false</code>
+ */
+ public boolean isNillable() {
+ return mNillable;
+ }
+
+ /**
+ * Prints the tag of the node (opening or closing).
+ *
+ * @param aIndent indent prefix for the tag
+ * @param aOutput output stream
+ * @param aOpening true if opening tag, false otherwise
+ * @param aFormat schema type
+ */
+ public void printTag(String aIndent, PrintStream aOutput,
+ boolean aOpening, int aFormat) {
+ aOutput.print(aIndent + (aOpening ? "<" : "</")) ;
+ aOutput.print(NodeParsing.PROP_TAG) ;
+ if (aOpening) {
+ aOutput.print(" " + getAttributes(aFormat)) ;
+ }
+ aOutput.print(">\n") ;
+ }
+
+ /**
+ * Outputs the property's contents to a PrintStream.
+ *
+ * @param aIndent indent prefix for the printing
+ * @param aOutput stream to print to
+ * @param aFormat schema type
+ */
+ public void printToStream(String aIndent,
+ PrintStream aOutput, int aFormat) {
+ printTag(aIndent, aOutput, true, aFormat) ;
+ printValue(aIndent + PolicyTree.TAB, aOutput, aFormat) ;
+ printTag(aIndent, aOutput, false, aFormat) ;
+ }
+
+
+ /**
+ * Prints the possible values.
+ *
+ * @param aIndent indent prefix for the printing
+ * @param aOutput stream to print to
+ * @param aFormat schema type
+ */
+ public void printValue(String aIndent,
+ PrintStream aOutput, int aFormat) {
+ if (mValues != null) {
+ NodeValueImpl value = null;
+ Enumeration values = mValues.elements();
+ if (values != null) {
+ while (values.hasMoreElements()) {
+ value = (NodeValueImpl)values.nextElement();
+ if (value != null) {
+ if (aFormat == XMLStreamable.UPDATE_SCHEMA) {
+ if (isAddedAtTopLayer() ||
+ value.isModifiedAtTopLayer()) {
+ value.printToStream(aIndent, aOutput);
+ }
+ } else {
+ value.printToStream(aIndent, aOutput);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Determines from this update property which operation is to
+ * be carried out during the read merge, and then invokes
+ * the corresponding operation method.
+ *
+ * @param aResultNode node that will be the result of
+ * the read merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ * @throws InvalidPropertyException if property is invalid
+ */
+ public void processReadOperation(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException {
+ /* Check the validity of the configuration node */
+ if (mName == null ) {
+ throw new InvalidPropertyException();
+ }
+ /* determine the operation to be carried out */
+ switch (mOperationType) {
+ case OperationType.OP_REPLACE:
+ readReplaceProperty(aResultNode, aUpdateNodeKey,
+ aUpdateNodePath, aIsParentUpdateLayer);
+ break;
+ case OperationType.OP_UNKNOWN: //defaults to OP_MODIFY
+ case OperationType.OP_MODIFY:
+ readModifyProperty(aResultNode, aUpdateNodeKey,
+ aUpdateNodePath, aIsParentUpdateLayer);
+ break;
+ };
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param aValue the value
+ * @param aDataType the type of the data
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void put(String aValue, DataType aDataType) throws SPIException ;
+
+ /**
+ * Sets the string value.
+ *
+ * @param aValue the string value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putString(String aValue) throws SPIException;
+
+ /**
+ * Sets the hexbinary value as a string.
+ *
+ * @param aValue the hexbinary value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putHexBinary(String aValue) throws SPIException;
+
+ /**
+ * Sets the int value.
+ *
+ * @param aValue the int value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putInt(int aValue) throws SPIException;
+
+ /**
+ * Sets the double value.
+ *
+ * @param aValue the double value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putDouble(double aValue) throws SPIException;
+
+ /**
+ * Sets the short value.
+ *
+ * @param aValue the short value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putShort(short aValue) throws SPIException;
+
+
+ /**
+ * Sets the long value.
+ *
+ * @param aValue the long value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putLong(long aValue) throws SPIException;
+
+ /**
+ * Sets the boolean value.
+ *
+ * @param aValue the boolean value
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putBoolean(boolean aValue) throws SPIException;
+
+
+ /**
+ * Sets the string list values.
+ *
+ * @param aValues the list of string values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putStringList(String[] aValues) throws SPIException;
+
+ /**
+ * Sets the hexbinary list values.
+ *
+ * @param aValues the list of hexbinary values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putHexBinaryList(String[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of int value.
+ *
+ * @param aValues the list of int values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putIntList(int[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of double values.
+ *
+ * @param aValue the list of double values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putDoubleList(double[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of short values.
+ *
+ * @param aValue the list of short values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putShortList(short[] aValues) throws SPIException;
+
+ /**
+ * Sets the list of long values.
+ *
+ * @param aValue the list of long values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putLongList(long []aValues) throws SPIException;
+
+ /**
+ * Sets the list of boolean values.
+ *
+ * @param aValue the list of boolean values
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void putBooleanList(boolean[] aValues) throws SPIException;
+
+ /**
+ * Carries out the read modification operation specified in
+ * this update node.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void readModifyProperty(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException ;
+
+ /**
+ * Carries out the replacement operation specified in
+ * this update node.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodePath the path to this update property (used
+ * for exception messages)
+ * @param aUpdateNodeKey information on update property
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public abstract void readReplaceProperty(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer)
+ throws SPIException ;
+
+ /**
+ * Sets the data type.
+ *
+ * @return the data type
+ */
+ public void setDataType(DataType aDataType) {
+ mDataType = aDataType;
+ }
+
+ /**
+ * Set the finalized attribute for the element.
+ *
+ * @param aSetting <code>true</code> or <code>false</code>
+ * @param aNameOfElementWhereProtectionSet
+ * @param aOriginOfProtection
+ */
+ public void setFinalized (boolean aSetting,
+ String aNameOfElementWhereProtectionSet,
+ Policy aOriginOfProtection) {
+ super.setFinalized(aSetting);
+ mNameOfElementWhereProtectionSet = aNameOfElementWhereProtectionSet;
+ mOriginOfProtection = aOriginOfProtection;
+ }
+
+
+ /**
+ * Sets the localized flag to true. Only properties
+ * defined in the schema may have this attribute.
+ *
+ */
+ public void setLocalized() {
+ mLocalized = true;
+ }
+
+
+ /**
+ * Sets the property value to Nil.
+ *
+ * @throws <code>SPIException</code>
+ */
+ public abstract void setNil() throws SPIException ;
+
+
+ /**
+ * Sets the nillable flag indicating whether or not
+ * a property may assume the value nil. A property is
+ * nillable by default.
+ *
+ * @param aNillable <code>true</code> if node is
+ * nillable, otherwise <code>false</code>
+ */
+ public void setNillable(boolean aNillable) {
+ mNillable = aNillable;
+ }
+
+ /**
+ * Sets a new value if the property is not read only.
+ *
+ * @param aValue node value
+ * @param aLocale locale
+ * @throws <code>SPIException</code> if
+ * property is readonly
+ */
+ public void setNodeValue(NodeValueImpl aValue, String aLocale)
+ throws SPIException {
+ /* if property node is readonly then its value may not be changed */
+ checkIfReadOnly();
+ aValue.setPropertyImpl(this);
+ if (mValues == null) { mValues = new Hashtable(); }
+ if (!mLocalized || aLocale == null ||
+ aLocale.equals(PolicyTree.DEFAULT_LOCALE_NAME)) {
+ mValues.put(PolicyTree.DEFAULT_LOCALE_NAME, aValue);
+ } else {
+ mValues.put(aLocale, aValue);
+ }
+ }
+
+ /**
+ * Sets the layer where the property originated.
+ *
+ * @param aOriginLayer id of the layer where the node originated
+ */
+ public void setOrigin (Policy aOriginLayer) {
+ mOriginLayer = aOriginLayer;
+ if (mValues != null) {
+ Enumeration values = mValues.elements();
+ if (values != null) {
+ while (values.hasMoreElements()) {
+ ((NodeValueImpl)values.nextElement()).setOrigin(aOriginLayer);
+ }
+ }
+ }
+ }
+
+ /**
+ * Used during parsing to set a new value.
+ *
+ * @param aValue node value
+ * @param aLocale locale
+ */
+ public void setParsedValue(NodeValueImpl aValue, String aLocale) {
+ if (mValues == null) { mValues = new Hashtable(); }
+ aValue.setPropertyImpl(this);
+ if (aLocale == null ||
+ aLocale.equals(PolicyTree.DEFAULT_LOCALE_NAME)) {
+ mValues.put(PolicyTree.DEFAULT_LOCALE_NAME, aValue);
+ } else {
+ mValues.put(aLocale, aValue);
+ }
+ }
+
+
+ /**
+ * Sets the required locale.
+ *
+ * @param aRequiredLocale the locale specified
+ * by java proxy
+ */
+ public void setRequiredLocale(String aRequiredLocale) {
+ /* if the required locale is null or the default
+ locale then no action is required */
+ if (aRequiredLocale != null ||
+ !aRequiredLocale.equals(PolicyTree.DEFAULT_LOCALE_NAME)) {
+ mRequiredLocale = aRequiredLocale;
+ }
+ }
+
+ /**
+ * Sets the separator used by the property's values.
+ *
+ * @param aSeparator separator
+ */
+ public abstract void setSeparator(String aSeparator) ;
+
+ /**
+ * Sets the path, originating layer and dynamic
+ * settings for this property.
+ *
+ * @param aPath path name for this property
+ * @param aOriginLayer layer where property originated
+ * @param aIsParentLayer <code>true</code> true if
+ * data sourced from parent layer,
+ * otherwise <code>false</code>
+ */
+ public void setSettingsForAddedProperty(String aPath,
+ Policy aOriginLayer, boolean aIsParentLayer ) {
+ setPath(aPath);
+ if (aOriginLayer != null) { setOrigin(aOriginLayer); }
+ if (!aIsParentLayer) {
+ setAddedAtTopLayer();
+ }
+ }
+
+ /**
+ * Returns a copy of the property.
+ *
+ * @return copy of the property
+ * @throws <code>SPIException</code> if cannot
+ * create copy
+ */
+ public ConfigElementImpl shallowCopy() throws SPIException {
+ ConfigElementImpl returnProperty = super.shallowCopy();
+ if (mValues != null && !mValues.isEmpty()) {
+ ((PropertyImpl)returnProperty).mValues =
+ copyNodeValueImplTable(mValues,
+ (PropertyImpl)returnProperty);
+ }
+ ((PropertyImpl)returnProperty).mSeparator = mSeparator;
+ ((PropertyImpl)returnProperty).mNameOfElementWhereProtectionSet =
+ mNameOfElementWhereProtectionSet;
+ ((PropertyImpl)returnProperty).mOriginOfProtection =
+ mOriginOfProtection;
+ ((PropertyImpl)returnProperty).mOriginLayer =
+ mOriginLayer;
+ ((PropertyImpl)returnProperty).mRequiredLocale = mRequiredLocale;
+ ((PropertyImpl)returnProperty).mDataType = mDataType;
+ return returnProperty;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/property/ReadWritePropertyImpl.java b/src/com/sun/apoc/spi/cfgtree/property/ReadWritePropertyImpl.java
new file mode 100644
index 0000000..bd0167c
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/property/ReadWritePropertyImpl.java
@@ -0,0 +1,967 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.property;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.ConfigElementImpl;
+import com.sun.apoc.spi.cfgtree.DataType;
+import com.sun.apoc.spi.cfgtree.InvalidDataTypeException;
+import com.sun.apoc.spi.cfgtree.MandatoryElementException;
+import com.sun.apoc.spi.cfgtree.NodeKey;
+import com.sun.apoc.spi.cfgtree.NodeValueImpl;
+import com.sun.apoc.spi.cfgtree.OperationType;
+import com.sun.apoc.spi.cfgtree.PolicyTree;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNodeImpl;
+import com.sun.apoc.spi.cfgtree.policynode.ReadWritePolicyNodeImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Class for a property.
+ *
+ */
+public class ReadWritePropertyImpl extends PropertyImpl {
+ /** Default property */
+ private ReadWritePropertyImpl mDefaultProperty ;
+ private boolean mHasBeenModified = false;
+
+ /**
+ * Creates and adds a default <code>NodeValueImpl</code>.
+ *
+ * @param aOrigin originating layer
+ */
+ public void addDefaultNodeValueImpl(Policy aOrigin) {
+ if (mValues == null) { mValues = new Hashtable(); }
+ NodeValueImpl defaultValue = createDefaultNodeValueImpl();
+ defaultValue.setOrigin(aOrigin);
+ mValues.put(mRequiredLocale, defaultValue);
+ }
+
+ /**
+ * Clears the settings added at this layer.
+ *
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void clear() throws SPIException {
+ /* cannot apply reset operation if property
+ is readonly */
+ checkIfReadOnly();
+ ReadWritePropertyImpl defaultProperty = mDefaultProperty;
+ PolicyNodeImpl parent = (PolicyNodeImpl)getParent();
+ if (defaultProperty != null) {
+ setDefaultProperty(defaultProperty);
+ defaultProperty.setOperationType(OperationType.OP_RESET);
+ /* replace the property in the policy tree with
+ the default property. */
+ if (parent.isProtected()) {
+ defaultProperty.setFinalized(true,
+ getNameOfElementWhereProtectionSet(),
+ getOriginOfProtection());
+ parent.addProperty(defaultProperty);
+ }
+ } else {
+ /* we are dealing with a property added at this layer */
+ checkIfMandatory();
+ setOperationType(OperationType.OP_REMOVE);
+ }
+ mHasBeenModified = true;
+ }
+
+ /**
+ * Utility function for copying updated <code>NodeValueImpls</code>
+ * into an existing table of <code>NodeValueImpls</code>.
+ *
+ * @param aUpdateTable the table to be copied
+ * @param aPropertyImpl the property containing the table
+ * to be updated
+ * @param aLayer layer where values originated
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void copyUpdateNodeValueImpls(Hashtable aUpdateTable,
+ PropertyImpl aPropertyImpl, Policy aLayer,
+ boolean aIsParentUpdateLayer) throws SPIException {
+ Enumeration keys = aUpdateTable.keys();
+ if (keys != null) {
+ while (keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ NodeValueImpl updatedNodeValueImpl =
+ (NodeValueImpl)aUpdateTable.get(key);
+ if (updatedNodeValueImpl != null) {
+ /* if the property node is not nillable, then
+ ensure that don't copy a nil NodeValueImpl */
+ if (!aPropertyImpl.isNillable() &&
+ updatedNodeValueImpl.hasNilAttribute()) {
+ /* skip this value */
+ } else {
+ NodeValueImpl newNodeValueImpl =
+ updatedNodeValueImpl.copyNodeValueImpl();
+ newNodeValueImpl.setOrigin(aLayer);
+ aPropertyImpl.setNodeValue(newNodeValueImpl, key);
+ newNodeValueImpl.setPropertyImpl(aPropertyImpl);
+ if (!aIsParentUpdateLayer) {
+ newNodeValueImpl.setModifiedAtTopLayer();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes this property if it is dynamic.
+ *
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public void delete () throws SPIException {
+ /* if this property is marked readonly then it cannot
+ be removed */
+ checkIfReadOnly();
+ /* only properties that have been added in the current
+ layer may be removed */
+ if (! ((PropertyImpl)this).isAddedAtTopLayer()) {
+ throw new MandatoryElementException(
+ "Property", getName(),
+ MandatoryElementException.REMOVE_MANDATORY_KEY);
+ }
+ /* set the operation attribute to "remove" */
+ setOperationType(OperationType.OP_REMOVE);
+ mHasBeenModified = true;
+ }
+
+ /**
+ * Returns the default property, that is the property as it
+ * was in the default layer.
+ *
+ * @return the default property
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ReadWritePropertyImpl getDefaultProperty()
+ throws SPIException {
+ return ( (mDefaultProperty != null) ?
+ (ReadWritePropertyImpl)mDefaultProperty.shallowCopy() : null);
+ }
+
+ /**
+ * Returns a boolean indicating if the property has
+ * been modified.
+ *
+ * @return <code>true</code> if the property has been
+ * modified, otherwise <code>false</code>
+ */
+ public boolean hasBeenModified() {
+ return mHasBeenModified;
+ }
+
+
+ /**
+ * Determines from this update operation which operation is to
+ * be carried out during the read merge, and then invokes
+ * the corresponding operation method.
+ *
+ * @param aOutputProperty the equivalent property for the new
+ * update layer
+ * @param aLayer layer to update
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public boolean processUpdateOperation(PropertyImpl aOutputProperty,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ boolean update = false;
+ switch (mOperationType) {
+ case OperationType.OP_REPLACE:
+ update = updateReplaceProperty(aOutputProperty, aLayer,
+ aUpdateNodePath);
+ break;
+ case OperationType.OP_REMOVE:
+ update = updateRemoveProperty(aOutputProperty, aLayer,
+ aUpdateNodePath);
+ break;
+ case OperationType.OP_RESET:
+ update = updateResetProperty(aOutputProperty, aLayer,
+ aUpdateNodePath);
+ break;
+ case OperationType.OP_UNKNOWN: //defaults to OP_MODIFY
+ case OperationType.OP_MODIFY:
+ update = updateModifyProperty(aOutputProperty, aLayer,
+ aUpdateNodePath);
+ break;
+ };
+ return update;
+ }
+
+ private String[] getArrayFromListValue(String aValue) {
+ StringTokenizer st = new StringTokenizer(aValue, mSeparator);
+ String [] retCode = new String[st.countTokens()];
+ int i = 0;
+ while (st.hasMoreTokens()) {
+ retCode [i++] = st.nextToken();
+ }
+ return retCode;
+ }
+
+ private String getStringFromArray(String[] aValues) {
+ StringBuffer sBuf = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ for (int i = 0; i < aValues.length - 1; ++i) {
+ sBuf.append(aValues[i]);
+ sBuf.append(mSeparator);
+ }
+ sBuf.append(aValues[aValues.length - 1]);
+ return sBuf.toString();
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param aValue the value
+ * @param aDataType the type of the data
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void put(String aValue, DataType aDataType) throws SPIException {
+ if (aValue == null) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ if (mDataType == DataType.UNKNOWN) {
+ mDataType = aDataType;
+ } else if (mDataType != aDataType) {
+ throw new InvalidDataTypeException(
+ mDataType.getStringValue());
+ }
+ getNodeValue().setNewContents(aValue);
+ mHasBeenModified = true;
+ }
+
+ /**
+ * Sets the string value.
+ *
+ * @param aValue the string value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putString(String aValue) throws SPIException{
+ put(aValue, DataType.STRING);
+ }
+
+ /**
+ * Sets the hexbinary value as a string.
+ *
+ * @param aValue the hexbinary value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putHexBinary(String aValue) throws SPIException{
+ put(aValue, DataType.HEXBIN);
+ }
+
+ /**
+ * Sets the int value.
+ *
+ * @param aValue the int value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putInt(int aValue) throws SPIException{
+ put(Integer.toString(aValue), DataType.INT);
+ }
+
+ /**
+ * Sets the double value.
+ *
+ * @param aValue the double value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putDouble(double aValue) throws SPIException{
+ put(Double.toString(aValue), DataType.DOUBLE);
+ }
+
+ /**
+ * Sets the short value.
+ *
+ * @param aValue the short value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putShort(short aValue) throws SPIException{
+ put(Short.toString(aValue), DataType.SHORT);
+ }
+
+
+ /**
+ * Sets the long value.
+ *
+ * @param aValue the long value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putLong(long aValue) throws SPIException{
+ put(Long.toString(aValue), DataType.LONG);
+ }
+
+ /**
+ * Sets the boolean value.
+ *
+ * @param aValue the boolean value
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putBoolean(boolean aValue) throws SPIException{
+ put(Boolean.toString(aValue), DataType.BOOLEAN);
+ }
+
+ /**
+ * Sets the string list values.
+ *
+ * @param aValues the list of string values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void putStringList(String[] aValues) throws SPIException{
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ put(getStringFromArray(aValues), DataType.STRING_LIST);
+ }
+
+ /**
+ * Sets the hexbinary list values.
+ *
+ * @param aValues the list of hexbinary values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ */
+ public void putHexBinaryList(String[] aValues) throws SPIException{
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ put(getStringFromArray(aValues), DataType.HEXBIN_LIST);
+ }
+
+ /**
+ * Sets the list of int value.
+ *
+ * @param aValues the list of int values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void putIntList(int[] aValues) throws SPIException{
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ StringBuffer sBuf = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ for (int i = 0; i < aValues.length - 1; ++i) {
+ sBuf.append(aValues[i]);
+ sBuf.append(mSeparator);
+ }
+ sBuf.append(aValues[aValues.length - 1]);
+ put(sBuf.toString(), DataType.INT_LIST);
+ }
+
+ /**
+ * Sets the list of double values.
+ *
+ * @param aValue the list of double values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void putDoubleList(double[] aValues) throws SPIException{
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ StringBuffer sBuf = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ for (int i = 0; i < aValues.length - 1; ++i) {
+ sBuf.append(aValues[i]);
+ sBuf.append(mSeparator);
+ }
+ sBuf.append(aValues[aValues.length - 1]);
+ put(sBuf.toString(), DataType.DOUBLE_LIST);
+ }
+
+ /**
+ * Sets the list of short values.
+ *
+ * @param aValue the list of short values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void putShortList(short[] aValues) throws SPIException {
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ StringBuffer sBuf = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ for (int i = 0; i < aValues.length - 1; ++i) {
+ sBuf.append(aValues[i]);
+ sBuf.append(mSeparator);
+ }
+ sBuf.append(aValues[aValues.length - 1]);
+ put(sBuf.toString(), DataType.SHORT_LIST);
+ }
+
+ /**
+ * Sets the list of long values.
+ *
+ * @param aValue the list of long values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void putLongList(long []aValues) throws SPIException{
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ StringBuffer sBuf = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ for (int i = 0; i < aValues.length - 1; ++i) {
+ sBuf.append(aValues[i]);
+ sBuf.append(mSeparator);
+ }
+ sBuf.append(aValues[aValues.length - 1]);
+ put(sBuf.toString(), DataType.LONG_LIST);
+ }
+
+ /**
+ * Sets the list of boolean values.
+ *
+ * @param aValue the list of boolean values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void putBooleanList(String[] aValues) throws SPIException{
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ put(getStringFromArray(aValues), DataType.BOOLEAN_LIST);
+ }
+
+ /**
+ * Sets the list of boolean values.
+ *
+ * @param aValue the list of boolean values
+ * @throws SPIException if error occurs
+ * @throws InvalidDataTypeException if invalid data type
+ * @throws InvalidPropertyException if invalid value
+ */
+ public void putBooleanList(boolean[] aValues) throws SPIException{
+ if (aValues == null || aValues.length == 0) {
+ throw new InvalidPropertyException(
+ InvalidPropertyException.INVALID_VALUE_KEY);
+ }
+ StringBuffer sBuf = new StringBuffer(PolicyTree.BUFFER_SIZE);
+ for (int i = 0; i < aValues.length - 1; ++i) {
+ sBuf.append(aValues[i]);
+ sBuf.append(mSeparator);
+ }
+ sBuf.append(aValues[aValues.length - 1]);
+ put(sBuf.toString(), DataType.BOOLEAN_LIST);
+ }
+
+ /**
+ * Carries out the read modification operation specified in
+ * this update node.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodeKey information on update node
+ * @param aUpdateNodePath the path to this update node (used
+ * for exception messages)
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void readModifyProperty(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer) throws SPIException {
+ /* If the property exists in the source layer and is marked
+ readonly then this operation is ignored */
+ PropertyImpl resultNode =
+ (PropertyImpl)aResultNode.getProperty(getName());
+ if (resultNode != null && resultNode.isReadOnly()) { return; }
+
+ PropertyImpl newProperty;
+ if (resultNode == null) {
+ newProperty = this;
+ if (!aIsParentUpdateLayer) {
+ newProperty.setAddedAtTopLayer();
+ }
+ } else {
+ newProperty = (PropertyImpl)resultNode.shallowCopy();
+ /* If the update node has empty tags then the new PropertyImpl
+ will keep the values of the source layer. Otherwise, the
+ new Node copies the updated values of the update layer */
+ if (mValues != null && !mValues.isEmpty()) {
+ copyUpdateNodeValueImpls(mValues, newProperty,
+ aUpdateNodeKey.mLayer, aIsParentUpdateLayer);
+ }
+ }
+ newProperty.setPath(PolicyNodeImpl.appendToPath(aResultNode.getAbsolutePath(), getName()));
+ /* Check if this update property is finalized. If it is, and this
+ is a parent update layer being processed, then set the
+ readonly attribute to true for this node. If it is
+ finalized and this is the source layer or this is not a
+ parent layer, then set the finalized attribute to true */
+ if (isProtected()) {
+ newProperty.setFinalized(true, newProperty.getAbsolutePath(),
+ getOriginOfProtection());
+ if (aIsParentUpdateLayer) {
+ newProperty.setReadOnly();
+ }
+ }
+ /* set the operation property to reflect that this node
+ was modified */
+ newProperty.setOperationType(OperationType.OP_MODIFY);
+ /* add the node to aResultNode */
+ aResultNode.addProperty(newProperty);
+ }
+
+ /**
+ * Carries out the replacement operation specified in
+ * this update node.
+ *
+ * @param aResultNode node that will be the result of
+ * the merge process
+ * @param aUpdateNodePath the path to this update property (used
+ * for exception messages)
+ * @param aUpdateNodeKey information on update property
+ * @param aIsParentUpdateLayer indicates if this is a parent update
+ * layer (needed for handling
+ * finalized attribute): <code>true</code>
+ * if final layer, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public void readReplaceProperty(PolicyNodeImpl aResultNode,
+ NodeKey aUpdateNodeKey, String aUpdateNodePath,
+ boolean aIsParentUpdateLayer)
+ throws SPIException {
+ /* if property element exists in source layer then
+ it cannot be replaced, so the operation is ignored */
+ if (aResultNode.getChild(getName()) != null) {
+ return;
+ } else {
+ /* Check if the update node is finalized. If it is, and it is
+ a parent update layer being processed, then set the readonly
+ attribute to true. If it is a default layer, or not a parent
+ layer, then set the finalized attribute to true */
+ if (isProtected()) {
+ String name = PolicyNodeImpl.appendToPath(
+ aResultNode.getAbsolutePath(),
+ getName());
+ setFinalized(true, name, getOriginOfProtection());
+ if (aIsParentUpdateLayer) {
+ setReadOnly();
+ }
+ }
+ /* if the update node is empty, then add a default NodeValueImpl */
+ if (mValues == null || mValues.isEmpty()) {
+ addDefaultNodeValueImpl(getOrigin());
+ }
+ if (aIsParentUpdateLayer) {
+ /* a node inserted at a parent layer is
+ mandatory to subsequent layers */
+ setMandatoryFlag();
+ setOriginOfMandatory(getOrigin());
+ }
+ /* if this is the entity layer being read, then
+ set the dynamic flag to indicate that the property
+ was added on the current layer */
+ if (!aIsParentUpdateLayer) {
+ setAddedAtTopLayer();
+ }
+ setPath(PolicyNodeImpl.appendToPath(aResultNode.getAbsolutePath(), getName()));
+ aResultNode.addProperty(this);
+ }
+ }
+
+ /**
+ * Sets the default property, that is the property as it was in the
+ * default layer.
+ *
+ * @param aDefaultProperty the default property
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public void setDefaultProperty(
+ ReadWritePropertyImpl aDefaultProperty) throws SPIException {
+ mDefaultProperty = aDefaultProperty;
+ }
+
+ /**
+ * Sets the property value to Nil.
+ *
+ * @throws <code>SPIException</code>
+ */
+ public void setNil() throws SPIException {
+ getNodeValue().setValueToNil();
+ mHasBeenModified = true;
+ }
+
+ /**
+ * Sets the value of the finalized property of the property.
+ *
+ * @param aIsProtected <code>true</code> if the property
+ * is finalized, <code>false</code>
+ * otherwise
+ * if aIsProtected is <code>false</code>
+ */
+ public void setProtected(boolean aIsProtected)
+ throws SPIException {
+ setProtected(aIsProtected, getAbsolutePath(),
+ mPolicyTree.getPolicy());
+ }
+
+ /**
+ * Sets the value of the finalized property of the node,
+ * and its children.
+ *
+ * @param aIsProtected <code>true</code> if the node
+ * is finalized, <code>false</code>
+ * otherwise
+ * @param aNameOfNodeWhereProtectionSet name of the node where
+ * the flag was set
+ * (null if aIsProtected is
+ * <code>false</code>
+ * @param aOriginOfProtection layer where the flag was set
+ * (null if aIsProtected is
+ * <code>false</code>
+ */
+ public void setProtected(boolean aIsProtected,
+ String aNameOfNodeWhereProtectionSet,
+ Policy aOriginOfProtection)
+ throws SPIException {
+ checkIfReadOnly();
+ mIsProtected = aIsProtected ;
+ mNameOfElementWhereProtectionSet = aNameOfNodeWhereProtectionSet;
+ mOriginOfProtection = aOriginOfProtection;
+ mHasBeenModified = true;
+ }
+
+
+
+ /**
+ * Sets the property to its default.
+ *
+ * @param aDefaultProperty the default for the property on which
+ * the setDefault() method was called
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ private void setPropertyToDefault(
+ ReadWritePropertyImpl aDefaultProperty)
+ throws SPIException {
+ aDefaultProperty.setDefaultProperty(
+ (ReadWritePropertyImpl)aDefaultProperty.shallowCopy());
+ }
+
+
+ /**
+ * Sets the separator used by the property's values.
+ *
+ * @param aSeparator separator
+ */
+ public void setSeparator(String aSeparator) {
+ if (mSeparator != null) {
+ mSeparator = aSeparator;
+ }
+ mHasBeenModified = true;
+ }
+
+
+ /**
+ * Returns a shallow copy of the property.
+ *
+ * @return copy of the property
+ * @throws <code>SPIException</code> if cannot
+ * create copy
+ */
+ public ConfigElementImpl shallowCopy() throws SPIException {
+ ConfigElementImpl retCode = super.shallowCopy();
+ ((ReadWritePropertyImpl)retCode).mDefaultProperty = mDefaultProperty;
+ return retCode;
+ }
+
+ /**
+ * Carries out the update merge modification operation specified in
+ * this result property.
+ *
+ * @param aOutputProperty the equivalent node for the new
+ * update layer
+ * @param aLayer layer to be updated
+ * @param aUpdateNodePath the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public boolean updateModifyProperty(PropertyImpl aOutputProperty,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException{
+ boolean update = false;
+ if (isProtected()) {
+ if (getParent() == null || !getParent().isProtected()) {
+ /* should be included if the protect or setMandatory
+ function was applied directly to this node. */
+ update = true;
+ }
+ } else if (isMandatory() &&
+ (getOriginOfMandatory()).equals(aLayer)) {
+ update = true;
+ } else if (mValues != null) {
+ /* if the property was added at this layer
+ then all the values should be written */
+ if (isAddedAtTopLayer()) {
+ update = true;
+ } else {
+ /* go through each NodeValueImpl and see if it was
+ modified at this layer */
+ Enumeration keys = mValues.keys();
+ if (keys != null) {
+ Hashtable updateValues = null;
+ while (keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ NodeValueImpl value = (NodeValueImpl)getNodeValue(key);
+ if (value != null) {
+ if (value.isModifiedAtTopLayer()) {
+ update = true;
+ if (updateValues == null) {
+ updateValues = new Hashtable();
+ aOutputProperty.mValues =
+ updateValues;
+ }
+ updateValues.put(key, value);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!update) {
+ ((ReadWritePolicyNodeImpl)aOutputProperty.getParent()).removeProperty(
+ getName());
+ }
+ return update;
+ }
+
+
+
+ /**
+ * Carries out the update merge remove operation specified in
+ * this result node.
+ *
+ * @param aOutputProperty the equivalent node for the new
+ * update layer
+ * @param aLayer layer to be updated
+ * @param aUpdateNodePath the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean updateRemoveProperty(PropertyImpl aOutputProperty,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ ReadWritePolicyNodeImpl parentNode =
+ (ReadWritePolicyNodeImpl)getParent();
+ // delete the node
+ parentNode.removeProperty(getName());
+ return false;
+ }
+
+ /**
+ * Carries out the update merge replacement operation specified in
+ * this result property.
+ *
+ * @param aOutputProperty the equivalent property for the new
+ * update layer
+ * @param aLayer layer to be updated
+ * @param aUpdateNodePat the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean updateReplaceProperty(PropertyImpl aOutputProperty,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ boolean update = false;
+ if (isProtected()) {
+ if (getParent() == null || !getParent().isProtected()) {
+ /* should be included if the protect or setMandatory
+ function was applied directly to this node. */
+ update = true;
+ }
+ } else if (isMandatory() &&
+ (getOriginOfMandatory()).equals(aLayer)) {
+ update = true;
+ } else if (mValues != null) {
+ /* if the property was added at this layer
+ then all the values should be written */
+ if (isAddedAtTopLayer()) {
+ update = true;
+ } else {
+ /* go through each NodeValueImpl and see if it was
+ modified at this layer */
+ Enumeration keys = mValues.keys();
+ if (keys != null) {
+ Hashtable updateValues = null;
+ while (keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ NodeValueImpl value = (NodeValueImpl)getNodeValue(key);
+ if (value != null) {
+ if (value.isModifiedAtTopLayer()) {
+ update = true;
+ if (updateValues == null) {
+ updateValues = new Hashtable();
+ ((PropertyImpl)aOutputProperty).mValues =
+ updateValues;
+ }
+ updateValues.put(key, value);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (update) {
+ /* set the operation attribute to "modify" */
+ setOperationType(OperationType.OP_MODIFY);
+ aOutputProperty.setOperationType(OperationType.OP_MODIFY);
+ } else {
+ ((ReadWritePolicyNodeImpl)aOutputProperty.getParent()).removeProperty(
+ getName());
+ }
+ return update;
+ }
+
+ /**
+ * Carries out the update merge reset operation specified in
+ * this result node.
+ *
+ * @param aOutputNode the equivalent property for the new
+ * update layer
+ * @param aLayer layer to be updated
+ * @param aUpdateNodePath the path to this result node (used
+ * for exception messages
+ * @return <code>true</code> if this node is
+ * required for the new update layer,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public boolean updateResetProperty(PropertyImpl aOutputNode,
+ Policy aLayer,
+ String aUpdateNodePath)
+ throws SPIException {
+ boolean update = false;
+ if (isProtected()) {
+ if (getParent() == null || !getParent().isProtected()) {
+ /* it should be included if the protect function was
+ applied directly to this node. */
+ update = true;
+ }
+ } else if (isMandatory() && getOriginOfMandatory() != null &&
+ aLayer.equals(getOriginOfMandatory())) {
+ update = true;
+ } else if (mValues != null) {
+ /* go through each NodeValueImpl and see if it was
+ modified at this layer */
+ Enumeration keys = mValues.keys();
+ if (keys != null) {
+ Hashtable updateValues = null;
+ while (keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ NodeValueImpl value = (NodeValueImpl)getNodeValue(key);
+ if (value != null) {
+ if (value.isModifiedAtTopLayer()) {
+ update = true;
+ if (updateValues == null) {
+ updateValues = new Hashtable();
+ aOutputNode.mValues = updateValues;
+ }
+ updateValues.put(key, value);
+ }
+ }
+ }
+ }
+ }
+ if (update) {
+ /* set the operation attribute to "modify" */
+ aOutputNode.setOperationType(OperationType.OP_MODIFY);
+ }
+ return update;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeConverterImpl.java b/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeConverterImpl.java
new file mode 100644
index 0000000..f809ec7
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeConverterImpl.java
@@ -0,0 +1,124 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.readwrite;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.NodeKey;
+import com.sun.apoc.spi.cfgtree.PolicyTree;
+import com.sun.apoc.spi.cfgtree.PolicyTreeConverter;
+import com.sun.apoc.spi.cfgtree.PolicyTreeImpl;
+import com.sun.apoc.spi.cfgtree.XMLStreamable;
+import com.sun.apoc.spi.cfgtree.policynode.ReadWritePolicyNodeImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Implementation for a read/write PolicyTree Converter.
+ *
+ */
+public class ReadWritePolicyTreeConverterImpl implements PolicyTreeConverter{
+
+ /**
+ * Returns the <code>Policy</code> object derived from the
+ * <code>PolicyTree</code>.
+ *
+ * @param aPolicyTree the policy tree
+ * @return the <code>Policye</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public Policy getPolicy(PolicyTree aPolicyTree)
+ throws SPIException {
+ NodeKey nodeKey = new NodeKey();
+ nodeKey.mLayer = ((PolicyTreeImpl)aPolicyTree).getTopPolicy();
+ ReadWritePolicyNodeImpl updateNode =
+ (ReadWritePolicyNodeImpl)aPolicyTree.getRootNode();
+ ReadWritePolicyNodeImpl newNode = null;
+ /* find the updates specific to this layer */
+ newNode = createUpdateNode(updateNode, nodeKey.mLayer);
+ String outputData = null;
+ /* the newNode may be null if no update is required */
+ if (newNode != null) {
+ ByteArrayOutputStream streamOutput =
+ new ByteArrayOutputStream();
+ PrintStream output = new PrintStream(streamOutput);
+ newNode.printToStream("", output, XMLStreamable.UPDATE_SCHEMA);
+ outputData = streamOutput.toString();
+ }
+ Policy topPolicy = ((PolicyTreeImpl)aPolicyTree).getTopPolicy();
+ Policy newPolicy = new Policy(topPolicy.getId(),
+ topPolicy.getProfileId(), outputData);
+ return newPolicy;
+ }
+
+ /**
+ * Creates the new update node to write to the backend.
+ *
+ * @param aUpdateNode the updated node
+ * @param aLayer the layer to update
+ * @return the new update layer node, or null
+ * if no updates were detected
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ private ReadWritePolicyNodeImpl createUpdateNode(
+ ReadWritePolicyNodeImpl aUpdateNode, Policy aLayer)
+ throws SPIException {
+ ReadWritePolicyNodeImpl outputNode =
+ (ReadWritePolicyNodeImpl)aUpdateNode.shallowCopy();
+ String updatePath = (String)aUpdateNode.getPackage() + "." +
+ aUpdateNode.getName() + PolicyTree.PATH_SEPARATOR;
+ /* process nodes from update node.*/
+ boolean childrenUpdate =
+ aUpdateNode.processUpdateNodeChildren(outputNode,
+ aLayer, updatePath);
+ if (!childrenUpdate) {
+ /* as there are no updates for the child nodes, a
+ write will only be required if the component node
+ has been marked as finalized */
+ if (aUpdateNode.isProtected()) {
+ outputNode =
+ (ReadWritePolicyNodeImpl)aUpdateNode.shallowCopy();
+ } else {
+ outputNode = null;
+ }
+ }
+ return outputNode;
+ }
+}
diff --git a/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeFactoryImpl.java b/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeFactoryImpl.java
new file mode 100644
index 0000000..b57cf8e
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeFactoryImpl.java
@@ -0,0 +1,115 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.readwrite;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.xml.sax.XMLReader;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.PolicyTree;
+import com.sun.apoc.spi.cfgtree.PolicyTreeFactoryImpl;
+import com.sun.apoc.spi.policies.InvalidPolicyException;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Implementation for a read write policy tree.
+ *
+ */
+public class ReadWritePolicyTreeFactoryImpl extends PolicyTreeFactoryImpl {
+ private static final String MODULE = "ReadWritePolicyTreeFactoryImpl";
+
+ /**
+ * Returns the read/write <code>PolicyTree</code> object
+ * derived from the <code>Iterator</code> of policies.
+ *
+ * @param aPolicies policies
+ * @return the <code>PolicyTree</code> object
+ * @throws SPIException if error occurs
+ * @throws InvalidPolicyException if aPolicies is null or empty
+ *
+ */
+ public PolicyTree getPolicyTree(Iterator aPolicies)
+ throws SPIException {
+ if (aPolicies == null || !aPolicies.hasNext()) {
+ throw new InvalidPolicyException(
+ InvalidPolicyException.NULL_POLICIES_KEY);
+ }
+ ArrayList policyList = new ArrayList();
+ while (aPolicies.hasNext()) {
+ policyList.add(aPolicies.next());
+ }
+ return createReadWritePolicyTree(policyList);
+ }
+
+ /**
+ * Returns the <code>PolicyTree</code> object derived from the
+ * policy.
+ *
+ * @param aPolicy policy object
+ * @return the <code>PolicyTree</code> object
+ * @throws SPIException if error occurs
+ * @throws InvalidPolicyException if aPolicy is null
+ */
+ public PolicyTree getPolicyTree(Policy aPolicy)
+ throws SPIException {
+ if (aPolicy == null) {
+ throw new InvalidPolicyException();
+ }
+ ArrayList policyList = new ArrayList();
+ policyList.add(aPolicy);
+ return createReadWritePolicyTree(policyList);
+ }
+
+ /**
+ * Creates the read/write <code>PolicyTree</code> object derived from the
+ * list of policies.
+ *
+ * @param aPolicies policies
+ * @return the <code>PolicyTree</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public PolicyTree createReadWritePolicyTree(ArrayList aPolicies)
+ throws SPIException {
+ XMLReader reader = super.getXMLReader();
+ return new ReadWritePolicyTreeImpl(aPolicies, reader);
+ }
+
+}
+
diff --git a/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeImpl.java b/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeImpl.java
new file mode 100644
index 0000000..3d51fdf
--- /dev/null
+++ b/src/com/sun/apoc/spi/cfgtree/readwrite/ReadWritePolicyTreeImpl.java
@@ -0,0 +1,396 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.cfgtree.readwrite;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.cfgtree.NodeKey;
+import com.sun.apoc.spi.cfgtree.NodeParsing;
+import com.sun.apoc.spi.cfgtree.OperationType;
+import com.sun.apoc.spi.cfgtree.PolicyTree;
+import com.sun.apoc.spi.cfgtree.PolicyTreeImpl;
+import com.sun.apoc.spi.cfgtree.XMLPolicyTreeException;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNode;
+import com.sun.apoc.spi.cfgtree.policynode.PolicyNodeImpl;
+import com.sun.apoc.spi.cfgtree.policynode.ReadWritePolicyNodeImpl;
+import com.sun.apoc.spi.cfgtree.property.PropertyImpl;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Interface for a read write policy tree.
+ *
+ */
+public class ReadWritePolicyTreeImpl extends PolicyTreeImpl {
+ private XMLReader mReader;
+ private NodeParsing mParser = new NodeParsing();
+ private static final String MODULE = "PolicyTreeImpl";
+
+ /**
+ * Constructor for the class.
+ *
+ * @param aPolicies list of policies
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public ReadWritePolicyTreeImpl(ArrayList aPolicies, XMLReader aReader)
+ throws SPIException{
+ mReader = aReader;
+ mParser.setPolicyTree(this);
+ mReader.setContentHandler(mParser);
+ mReader.setErrorHandler(mParser);
+ ReadWritePolicyNodeImpl rootNode =
+ createRootNode(aPolicies);
+ super.setRootNode(rootNode);
+ }
+
+ /**
+ * Constructor for the class.
+ *
+ * @param aPolicy policy object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public ReadWritePolicyTreeImpl(Policy aPolicy, XMLReader aReader)
+ throws SPIException{
+ mReader = aReader;
+ mParser.setPolicyTree(this);
+ mReader.setContentHandler(mParser);
+ mReader.setErrorHandler(mParser);
+ ArrayList policyList = new ArrayList();
+ policyList.add(aPolicy);
+ ReadWritePolicyNodeImpl rootNode =
+ createRootNode(policyList);
+ super.setRootNode(rootNode);
+ }
+
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public PolicyNode createNode(String aPath) throws SPIException {
+ return createNode(aPath, false);
+ }
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the data path.
+ *
+ * @param aPath path for node
+ * @param aIsReplaceOp <code>true</code> if new node should have
+ * attribute "op=replace", otherwise
+ * <code>false</code>
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public PolicyNode createNode(String aPath, boolean aIsReplaceOp)
+ throws SPIException {
+ PolicyNodeImpl root = (PolicyNodeImpl)getRootNode();
+ root.checkIfReadOnly();
+ if (aPath == null) { return null; }
+ StringTokenizer st =
+ new StringTokenizer(aPath, PolicyTree.PATH_SEPARATOR);
+ if (st.hasMoreTokens()) {
+ String policyId = st.nextToken();
+ /* TO FIX
+ if (!policyId.equals(getTopPolicy().getId())) {
+ throw new SPIException("Invalid path specified.",
+ SPIException.ERROR_OCCURRED,
+ MODULE, 0);
+ }
+ */
+ }
+ int numOfNodes = st.countTokens();
+ PolicyNodeImpl newNode = null, childNode = null;
+ String childName = null;
+ if (numOfNodes != 0) {
+ /* create the intervening nodes if necessary */
+ for (int i = 1; i < numOfNodes ; ++i) {
+ childName = decodePath(st.nextToken());
+ childNode = root.getChildNode(childName);
+ if (childNode == null) {
+ root.addNode(childName);
+ }
+ root = root.getChild(childName);
+ }
+ childName = decodePath(st.nextToken());
+ /* check if the node to be created already exists, if it
+ does, then just return that node */
+ newNode = root.getChild(childName);
+ if (newNode != null &&
+ (newNode.getOperationType() != OperationType.OP_REMOVE)) {
+ return newNode;
+ }
+ newNode = (PolicyNodeImpl)((ReadWritePolicyNodeImpl)root).addNode(childName, aIsReplaceOp);
+ }
+ /* if no valid child then return the component node, otherwise
+ return the requested node */
+ return (childName == null) ? root : newNode;
+ }
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the list element for this data path.
+ *
+ * @param aPath path for node
+ * @return the <code>PolicyNode</code> object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ public PolicyNode createReplaceNode(String aPath) throws SPIException {
+ return createNode(aPath, true);
+ }
+
+ /**
+ * Creates and returns the <code>PolicyNode</code> object
+ * representing the root object.
+ *
+ * @param aPolicies <code>ArrayList</code> of policies
+ * @return the <code>ReadWritePolicyNodeImpl</code> object
+ * representing the root object
+ * @throws <code>SPIException</code> if error
+ * occurs
+ *
+ */
+ private ReadWritePolicyNodeImpl createRootNode(ArrayList aPolicies)
+ throws SPIException {
+ if (aPolicies.isEmpty()) { return null; }
+ checkPolicyIdsMatch(aPolicies);
+ int numOfPolicies = aPolicies.size();
+ Policy topPolicy = (Policy)aPolicies.get(numOfPolicies - 1);
+ super.setTopPolicy(topPolicy);
+ NodeKey nodeKey = new NodeKey();
+ nodeKey.mPolicyId = topPolicy.getId();
+ nodeKey.mLocale = PolicyTree.DEFAULT_LOCALE_NAME;
+ ReadWritePolicyNodeImpl rootNode = null, tmpNode = null;
+ boolean isParentUpdateLayer = true;
+ /* if only one policy then no merging is required,
+ however would still have to do some processing
+ of the node */
+ for (int i = 0; i < numOfPolicies ; ++i) {
+ Policy policy = (Policy)aPolicies.get(i);
+ nodeKey.mLayer = policy;
+ if (policy.getData() != null) {
+ tmpNode = parseData(policy.getData(), nodeKey);
+ }
+ if (tmpNode != null) {
+ checkLayerRootNodeValidity(tmpNode, topPolicy.getId());
+ if (isParentUpdateLayer && i == numOfPolicies - 1) {
+ isParentUpdateLayer = false;
+ /* set the default nodes, that is the
+ nodes as they would be if this
+ layer was not read */
+ if (rootNode != null) {
+ rootNode.addNodeDefaults();
+ }
+ }
+ if (rootNode == null) {
+ rootNode = tmpNode;
+ if (numOfPolicies == 1) {
+ rootNode.setSettingsForAddedNode(
+ rootNode.getPackage() +
+ "." + rootNode.getName(),
+ nodeKey.mLayer,
+ isParentUpdateLayer);
+ } else {
+ rootNode.expand(rootNode.getPackage() +
+ "." + rootNode.getName(),
+ isParentUpdateLayer);
+ }
+ if (isParentUpdateLayer) {
+ /* then go through node tree, setting
+ to readonly any nodes that are finalized */
+ rootNode.setReadOnly();
+ }
+ } else {
+ readMergeUpdateLayer(rootNode, tmpNode,
+ nodeKey, isParentUpdateLayer);
+ }
+ /* if the component node is marked readonly, then return */
+ if (rootNode.isReadOnly()) { break ; }
+ }
+ }
+ if (rootNode == null) {
+ rootNode = createRootNode(topPolicy);
+ }
+ if (isParentUpdateLayer) {
+ /* there is no data for this entity layer,
+ so set the default nodes */
+ rootNode.addNodeDefaults() ;
+ }
+ return rootNode;
+ }
+
+ /**
+ * Parses the XMLblob and returns a <code>ReadWritePolicyNodeImpl</code>
+ * representing this data.
+ *
+ * @param aPolicyData data to be parsed
+ * @param aNodeKey the <code>NodeKey</code> specifying the layer
+ * @return a <code>ReadWritePolicyNodeImpl</code>
+ * representing the data in the XMLblob
+ * @throws <code>SPIException</code> if error occurs
+ * when parsing data
+ */
+ private ReadWritePolicyNodeImpl parseData(String aPolicyData,
+ NodeKey aNodeKey) throws SPIException{
+ if (aPolicyData == null) { return null; }
+ StringReader input = new StringReader(aPolicyData);
+ InputSource source = new InputSource(input) ;
+ try {
+ mParser.setSourceLayer(aNodeKey.mLayer);
+ mParser.setLocale(aNodeKey.mLocale);
+ mParser.setPolicyId(aNodeKey.mPolicyId);
+ mReader.parse(source) ;
+ return (ReadWritePolicyNodeImpl)mParser.getRoot();
+ } catch (Exception e) {
+ throw new XMLPolicyTreeException(e);
+ }
+ }
+
+ /**
+ * Carries out the merge operation between the source
+ * layer and the next update layer.
+ *
+ * @param aResultNode the base node
+ * @param aUpdateLayer the update layer
+ * @param aUpdateNodeKey information on update node
+ * @param aIsParentUpdateLayer boolean indicating if parent layer
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ private void readMergeUpdateLayer(PolicyNodeImpl aResultNode,
+ PolicyNodeImpl aUpdateLayer, NodeKey aUpdateNodeKey,
+ boolean aIsParentUpdateLayer) throws SPIException {
+ String updatePath = aUpdateLayer.getPackage() + "." +
+ aResultNode.getName();
+ /* Check if this update node is protected. If it is, and this
+ is a parent layer being processed, then set the readonly
+ attribute to true for this node and its children. If it is,
+ finalized and this is not a parent layer, then set the finalized
+ attribute to true */
+ if (aUpdateLayer.isProtected()) {
+ aResultNode.setFinalized(true, aResultNode.getAbsolutePath(),
+ aUpdateLayer.getOriginOfProtection());
+ if (aIsParentUpdateLayer) {
+ aResultNode.setReadOnly();
+ }
+ }
+ /* process nodes from aUpdateLayer */
+ Vector updateChildrenNames = aUpdateLayer.getAllChildrenNames();
+ if (updateChildrenNames != null) {
+ /* path to current node in update layer, used for
+ exception messages */
+ updatePath += PolicyTree.PATH_SEPARATOR;
+ int size = updateChildrenNames.size();
+ for (int i = 0; i < size; i++) {
+ String name = (String)updateChildrenNames.get(i);
+ PolicyNodeImpl updateNode = null;
+ if (aUpdateLayer.getChildNodeTable() != null) {
+ updateNode =
+ (PolicyNodeImpl)aUpdateLayer.getChildNodeTable().get(name);
+ if (updateNode != null &&
+ updateNode.getName() != null) {
+ String childUpdatePath = updatePath +
+ updateNode.getName();
+ updateNode.processReadOperation(
+ aResultNode, aUpdateNodeKey,
+ childUpdatePath, aIsParentUpdateLayer);
+ }
+ }
+ if (updateNode == null &&
+ aUpdateLayer.getPropertyTable() != null) {
+ PropertyImpl updateProperty =
+ (PropertyImpl)aUpdateLayer.getPropertyTable().get(name);
+ if (updateProperty != null &&
+ updateProperty.getName() != null) {
+ String childUpdatePath = updatePath +
+ updateProperty.getName();
+ updateProperty.processReadOperation(
+ aResultNode, aUpdateNodeKey,
+ childUpdatePath, aIsParentUpdateLayer);
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Creates a root node where no policy data exists.
+ *
+ * @param aTopPolicy policy object
+ * @return root node
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ private ReadWritePolicyNodeImpl createRootNode(Policy aPolicy)
+ throws SPIException {
+ ReadWritePolicyNodeImpl returnNode =
+ new ReadWritePolicyNodeImpl();
+ String policyId = aPolicy.getId();
+ String packageName = null;
+ String name = null;
+ String separator = ReadWritePolicyNodeImpl.ID_SEPARATOR;
+ int lastIndex = policyId.lastIndexOf(separator);
+ if (lastIndex >= 0) {
+ packageName = policyId.substring(0, lastIndex);
+ name = policyId.substring(
+ lastIndex+separator.length());
+ }
+ returnNode.setPackage(packageName);
+ returnNode.setName(name);
+ returnNode.setPolicyTree(this);
+ returnNode.setOrigin(aPolicy);
+ return returnNode;
+ }
+}
diff --git a/src/com/sun/apoc/spi/copyright.txt b/src/com/sun/apoc/spi/copyright.txt
new file mode 100644
index 0000000..5a585ca
--- /dev/null
+++ b/src/com/sun/apoc/spi/copyright.txt
@@ -0,0 +1,3 @@
+Copyright © 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, California 95054, U.S.A. All rights reserved.Sun Microsystems, Inc. has intellectual property rights relating to technology embodied in the product that is described in this document. In particular, and without limitation, these intellectual property rights may include one or more of the U.S. patents listed at http://www.sun.com/patents and one or more additional patents or pending patent applications in the U.S. and in other countries.THIS PRODUCT CONTAINS CONFIDENTIAL INFORMATION AND TRADE SECRETS OF SUN MICROSYSTEMS, INC. USE, DISCLOSURE OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SUN MICROSYSTEMS, INC.U.S. Government Rights - Commercial software. Government users are subject to the Sun Microsystems, Inc. standard license agreement and applicable provisions of the FAR and its supplements. Use is subject to license terms. Sun, Sun Microsystems, the Sun logo, Java, Solaris, StarOffice, Sun Ray and Sun Desktop Manager are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries.All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. in the U.S. and other countries. Products bearing SPARC trademarks are based upon architecture developed by Sun Microsystems, Inc.UNIX is a registered trademark in the U.S. and other countries, exclusively licensed through X/Open Company, Ltd.This product is covered and controlled by U.S. Export Control laws and may be subject to the export or import laws in other countries. Nuclear, missile, chemical biological weapons or nuclear maritime end uses or end users, whether direct or indirect, are strictly prohibited. Export or reexport to countries subject to U.S. embargo or to entities identified on U.S. export exclusion lists, including, but not limited to, the denied persons and specially designated nationals lists is strictly prohibited.
+
+Copyright © 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, California 95054, Etats-Unis. Tous droits réservés.Sun Microsystems, Inc. détient les droits de propriété intellectuels relatifs à la technologie incorporée dans le produit qui est décrit dans ce document. En particulier, et ce sans limitation, ces droits de propriété intellectuelle peuvent inclure un ou plus des brevets américains listés à l'adresse http://www.sun.com/patents et un ou les brevets supplémentaires ou les applications de brevet en attente aux Etats - Unis et dans les autres pays.CE PRODUIT CONTIENT DES INFORMATIONS CONFIDENTIELLES ET DES SECRETS COMMERCIAUX DE SUN MICROSYSTEMS, INC. SON UTILISATION, SA DIVULGATION ET SA REPRODUCTION SONT INTERDITES SANS L AUTORISATION EXPRESSE, ECRITE ET PREALABLE DE SUN MICROSYSTEMS, INC.L'utilisation est soumise aux termes de la Licence.Sun, Sun Microsystems, le logo Sun, Java, Solaris, StarOffice, Sun Ray et Sun Desktop Manager sont des marques de fabrique ou des marques déposées de Sun Microsystems, Inc. aux Etats-Unis et dans d'autres pays.Toutes les marques SPARC sont utilisées sous licence et sont des marques de fabrique ou des marques déposées de SPARC International, Inc. aux Etats-Unis et dans d'autres pays. Les produits portant les marques SPARC sont basés sur une architecture développée par Sun Microsystems, Inc.UNIX est une marque déposée aux Etats-Unis et dans d'autres pays et licenciée exlusivement par X/Open Company, Ltd.Ce produit est soumis à la législation américaine en matière de contrôle des exportations et peut être soumis à la règlementation en vigueur dans d'autres pays dans le domaine des exportations et importations. Les utilisations, ou utilisateurs finaux, pour des armes nucléaires,des missiles, des armes biologiques et chimiques ou du nucléaire maritime, directement ou indirectement, sont strictement interdites. Les exportations ou réexportations vers les pays sous embargo américain, ou vers des entités figurant sur les listes d'exclusion d'exportation américaines, y compris, mais de manière non exhaustive, la liste de personnes qui font objet d'un ordre de ne pas participer, d'une façon directe ou indirecte, aux exportations des produits ou des services qui sont régis par la législation américaine en matière de contrôle des exportations et la liste de ressortissants spécifiquement désignés, sont rigoureusement interdites.
diff --git a/src/com/sun/apoc/spi/entities/AbstractEntity.java b/src/com/sun/apoc/spi/entities/AbstractEntity.java
new file mode 100644
index 0000000..99d6350
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/AbstractEntity.java
@@ -0,0 +1,214 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Locale ;
+import java.util.TreeSet;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileComparatorProvider;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+
+/**
+ * Abstract class for an entity.
+ */
+public abstract class AbstractEntity implements Entity
+{
+ protected String mId;
+ protected PolicySource mPolicySource;
+
+
+ public void setPolicySource(PolicySource aPolicySource) {
+ mPolicySource = aPolicySource;
+ }
+
+ /**
+ * Returns the id for this entity.
+ *
+ * @return the id
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Returns parent entity.
+ *
+ * @return parent entity
+ */
+ public abstract Entity getParent() ;
+
+ /**
+ * Returns the profile repository for this entity.
+ *
+ * @return the profile repository for this entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ProfileRepository getProfileRepository() throws SPIException {
+ return mPolicySource.getProfileProvider()
+ .getProfileRepository(this.getId());
+ }
+
+
+ /**
+ * Returns the profiles assigned to this entity.
+ *
+ * @return <code>Iterator</code> of profiles assigned
+ * to this entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getAssignedProfiles() throws SPIException {
+ return mPolicySource.getAssignmentProvider()
+ .getAssignedProfiles(this);
+ }
+
+ /**
+ * Assigns a profile to this entity.
+ *
+ * @param aProfile profile to assign
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void assignProfile(Profile aProfile) throws SPIException {
+ mPolicySource.getAssignmentProvider().assignProfile(this, aProfile);
+ }
+
+ /**
+ * Unassigns specified profile from this entity.
+ *
+ * @param aProfile profile to uassign
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void unassignProfile(Profile aProfile) throws SPIException {
+ mPolicySource.getAssignmentProvider()
+ .unassignProfile(this, aProfile);
+ }
+
+ /**
+ * Returns an iterator over all the parents for this entity.
+ *
+ * @return iterator over all the parents for this entity.
+ */
+ public Iterator getAllParents() {
+ ArrayList parents = new ArrayList();
+ Entity parent = getParent();
+ while (parent != null) {
+ parents.add(0, parent);
+ parent = parent.getParent();
+ }
+ return parents.iterator();
+ }
+
+ /**
+ * Returns an iterator of profiles
+ * that contribute to this entity's configuration data.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public abstract Iterator getLayeredProfiles() throws SPIException;
+
+ /**
+ * Returns an iterator of profiles assigned to the parents
+ * given in parameter and roles given in parameter
+ * and to the current entity.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @param parents iterator over the entities representing
+ * the parents of the current entity
+ * @param roles iterator over the entities representing
+ * the roles this entity is member of
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getLayeredProfiles(Iterator parents, Iterator roles)
+ throws SPIException {
+ ArrayList profiles = new ArrayList();
+
+ /* Add the parents profiles */
+ Iterator iterParentProfiles = null;
+ if (parents != null) {
+ while (parents.hasNext()) {
+ Entity parent = (Entity)parents.next();
+ iterParentProfiles = parent.getAssignedProfiles();
+ while (iterParentProfiles.hasNext()) {
+ profiles.add((Profile)iterParentProfiles.next());
+ }
+ }
+ }
+ /* get the s for the roles of which
+ this entity is a member */
+ if (roles != null) {
+ Comparator comparator =
+ ((ProfileComparatorProvider)mPolicySource.getProfileProvider())
+ .getProfileComparator();
+ TreeSet roleProfilesTree = new TreeSet(comparator);
+ while (roles.hasNext()) {
+ Entity role = (Entity)roles.next();
+ Iterator iterCurrentRole = role.getAssignedProfiles();
+ while (iterCurrentRole.hasNext()) {
+ roleProfilesTree.add(iterCurrentRole.next());
+ }
+ }
+ Iterator iterRoleProfilesTree = roleProfilesTree.iterator();
+ while (iterRoleProfilesTree.hasNext()) {
+ profiles.add((Profile)iterRoleProfilesTree.next());
+ }
+ }
+ /* get the s for the entity itself */
+ Iterator iterEntityProfiles = this.getAssignedProfiles();
+ while (iterEntityProfiles.hasNext()) {
+ profiles.add((Profile)iterEntityProfiles.next());
+ }
+ return profiles.iterator();
+ }
+
+ /**
+ * Returns the name of <code>PolicySource</code> for this entity
+ * @return the name of the <code>PolicySource</code>
+ */
+ public String getPolicySourceName() {
+ return mPolicySource.getName();
+ }
+}
diff --git a/src/com/sun/apoc/spi/entities/Domain.java b/src/com/sun/apoc/spi/entities/Domain.java
new file mode 100644
index 0000000..5c93e8c
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/Domain.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+
+import java.util.Iterator;
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Interface for an domain.
+ *
+ */
+public interface Domain extends Node
+{
+ /**
+ * Returns host entities contained by this domain.
+ *
+ * @return <code>Iterator</code> of child host entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getHosts() throws SPIException;
+
+ /**
+ * Returns subdomain objects.
+ *
+ * @return <code>Iterator</code> of subdomains contained by this domain
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getSubDomains() throws SPIException;
+
+ /**
+ * Returns domains that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for domains
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of domain objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findSubDomains(String aFilter, boolean aIsRecursive) throws SPIException;
+
+ /**
+ * Returns hosts that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for hosts
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of host objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findHosts(String aFilter, boolean aIsRecursive) throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/entities/DomainTreeProvider.java b/src/com/sun/apoc/spi/entities/DomainTreeProvider.java
new file mode 100644
index 0000000..aed7902
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/DomainTreeProvider.java
@@ -0,0 +1,53 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Provides access to an Domain Tree
+ * (composed of Domains, Roles and Hosts)
+ *
+ */
+public interface DomainTreeProvider extends EntityTreeProvider {
+
+ /**
+ * Returns the root domain node of the Domain Tree
+ *
+ * @return root node
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Domain getRootDomain() throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/entities/Entity.java b/src/com/sun/apoc/spi/entities/Entity.java
new file mode 100644
index 0000000..c0654e3
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/Entity.java
@@ -0,0 +1,149 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+
+import java.util.Iterator;
+import java.util.Locale ;
+
+import com.sun.apoc.spi.AssignmentProvider;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+
+/**
+ * Interface for an entity.
+ */
+public interface Entity
+{
+ /**
+ * Returns the display name for this entity.
+ *
+ * @param aLocale locale for the display
+ * @return the display name
+ */
+ public String getDisplayName(Locale aLocale) ;
+
+ /**
+ * Returns an interator over the display names of the ancestors
+ * of this entity, starting from the root entity down to the direct
+ * parent of this entity, reflecting the entity structure.
+ *
+ * @param aLocale locale for the display names
+ * @return display names of the ancestors
+ */
+ public Iterator getAncestorNames(Locale aLocale);
+
+ /**
+ * Returns the id for this entity.
+ *
+ * @return the id
+ */
+ public String getId() ;
+
+ /**
+ * Returns parent entity.
+ *
+ * @return parent entity
+ */
+ public Entity getParent() ;
+
+ /**
+ * Returns the profile repository for this entity.
+ *
+ * @return the profile repository for this entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ProfileRepository getProfileRepository() throws SPIException;
+
+ /**
+ * Returns the profiles assigned to this entity.
+ * Returns only the profiles that have an Applicability
+ * compatible with the entity type.
+ *
+ * @return <code>Iterator</code> of profiles assigned
+ * to this entity
+ * @throws <code>SPIException</code> if error occurs
+ * @see AssignmentProvider#assignProfile(Entity, Profile)
+ */
+ public Iterator getAssignedProfiles() throws SPIException;
+
+ /**
+ * Assigns a profile to this entity.
+ * Verify if the Applicability of the Profile is
+ * compatible with the type of Entity:
+ * a profile with Applicabity.USER can be assigned
+ * to a Organization, User or Role defined in an Organization
+ * a profile with Applicabity.HOST can be assigned
+ * to a Domain, Host or Role defined in Domain
+ * a profile with Applicabity.ALL can be assigned
+ * to any entity
+ *
+ * @param aProfile profile to assign
+ * @throws <code>SPIException</code> if error occurs
+ * or if Applicability of the profile is not
+ * compatible with the type of entity
+ * @see AssignmentProvider#assignProfile(Entity, Profile)
+ */
+ public void assignProfile(Profile aProfile) throws SPIException;
+
+ /**
+ * Unassigns specified profile from this entity.
+ *
+ * @param aProfile profile to uassign
+ * @throws <code>SPIException</code> if error occurs
+ * @see AssignmentProvider#unassignProfile(Entity, Profile)
+ */
+ public void unassignProfile(Profile aProfile) throws SPIException;
+
+ /**
+ * Returns an iterator of profiles
+ * that contribute to this entity's configuration data.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public Iterator getLayeredProfiles()
+ throws SPIException ;
+
+ /**
+ * Returns the name of <code>PolicySource</code> for this entity
+ * @return the name of the <code>PolicySource</code>
+ */
+ public String getPolicySourceName() ;
+}
diff --git a/src/com/sun/apoc/spi/entities/EntityException.java b/src/com/sun/apoc/spi/entities/EntityException.java
new file mode 100644
index 0000000..4d9fcfe
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/EntityException.java
@@ -0,0 +1,45 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+import com.sun.apoc.spi.SPIException;
+
+public class EntityException extends SPIException {
+
+ public EntityException () {
+ super();
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/entities/EntityTreeProvider.java b/src/com/sun/apoc/spi/entities/EntityTreeProvider.java
new file mode 100644
index 0000000..ff4d789
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/EntityTreeProvider.java
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+import com.sun.apoc.spi.Provider;
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Provides access to an Entity Tree
+ *
+ */
+public interface EntityTreeProvider extends Provider {
+
+ /**
+ * Returns the root node of the Entity Tree
+ *
+ * @return root node
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Node getRootEntity() throws SPIException;
+
+ /**
+ * Returns the entity for this id in the Entity Tree
+ *
+ * @param id id string
+ * @return entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity(String id) throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/entities/Host.java b/src/com/sun/apoc/spi/entities/Host.java
new file mode 100644
index 0000000..0be9bb3
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/Host.java
@@ -0,0 +1,46 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+
+
+/**
+ * Interface for a host entity.
+ *
+ */
+public interface Host extends Leaf
+{
+}
+
diff --git a/src/com/sun/apoc/spi/entities/InvalidEntityIdException.java b/src/com/sun/apoc/spi/entities/InvalidEntityIdException.java
new file mode 100644
index 0000000..b6065ea
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/InvalidEntityIdException.java
@@ -0,0 +1,39 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+public class InvalidEntityIdException extends EntityException {
+
+}
diff --git a/src/com/sun/apoc/spi/entities/InvalidFilterException.java b/src/com/sun/apoc/spi/entities/InvalidFilterException.java
new file mode 100644
index 0000000..9fc0923
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/InvalidFilterException.java
@@ -0,0 +1,55 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+public class InvalidFilterException extends EntityException {
+
+ private static final String NULL_FILTER_KEY =
+ "error.spi.entity.filter.null";
+
+ private static final String INVALID_FILTER_KEY =
+ "error.spi.entity.filter.invalid";
+
+ public InvalidFilterException () {
+ super();
+ mMessageKey = NULL_FILTER_KEY;
+ }
+
+ public InvalidFilterException (String filter) {
+ super();
+ mMessageKey = INVALID_FILTER_KEY;
+ mMessageParams = new Object[]{filter};
+ }
+}
diff --git a/src/com/sun/apoc/spi/entities/Leaf.java b/src/com/sun/apoc/spi/entities/Leaf.java
new file mode 100644
index 0000000..7b4572d
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/Leaf.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Interface for a leaf in the entity tree.
+ *
+ */
+public interface Leaf extends Entity {
+
+ /**
+ * Return list of roles of which this entity leaf is a member.
+ *
+ * @return <code>Iterator</code> listing roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getMemberships() throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/entities/NoSuchEntityException.java b/src/com/sun/apoc/spi/entities/NoSuchEntityException.java
new file mode 100644
index 0000000..af96c48
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/NoSuchEntityException.java
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+public class NoSuchEntityException extends EntityException {
+
+ private static final String NO_ENTITY_KEY =
+ "error.spi.entity.noexist";
+
+ private String mEntityId;
+
+ public NoSuchEntityException () {
+ super();
+ }
+
+ public NoSuchEntityException (String entityId) {
+ super();
+ mEntityId = entityId;
+ mMessageKey = NO_ENTITY_KEY;
+ mMessageParams = new Object[]{mEntityId};
+ }
+
+ public String getEntityId() { return mEntityId; }
+}
diff --git a/src/com/sun/apoc/spi/entities/Node.java b/src/com/sun/apoc/spi/entities/Node.java
new file mode 100644
index 0000000..d79132e
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/Node.java
@@ -0,0 +1,139 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Interface for a node in the entity tree.
+ *
+ */
+public interface Node extends Entity
+{
+ /**
+ * Returns contained entities that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for entities
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of entity objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findEntities(String aFilter, boolean aIsRecursive) throws SPIException;
+
+ /**
+ * Returns the child roles.
+ *
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getRoles () throws SPIException ;
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has roles.
+ *
+ * @return <code>true</code> if there are roles, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasRoles() throws SPIException ;
+
+ /**
+ * Returns child entities.
+ *
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getChildren() throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has children.
+ *
+ * @return <code>true</code> if there are children, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasChildren() throws SPIException ;
+
+ /**
+ * Returns leaf entities.
+ *
+ * @return <code>Iterator</code> of leaf entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getLeaves() throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has leaves.
+ *
+ * @return <code>true</code> if there are leaves, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasLeaves() throws SPIException ;
+
+ /**
+ * Returns node entities.
+ *
+ * @return <code>Iterator</code> of node entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getNodes() throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has nodes.
+ *
+ * @return <code>true</code> if there are nodes, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasNodes() throws SPIException ;
+
+ /**
+ * Returns the entity for this id.
+ *
+ * @param aId id string
+ * @return entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity(String aId) throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/entities/Organization.java b/src/com/sun/apoc/spi/entities/Organization.java
new file mode 100644
index 0000000..1e05158
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/Organization.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Interface for an organization.
+ *
+ */
+public interface Organization extends Node
+{
+ /**
+ * Returns user entities contained by this organization.
+ *
+ * @return <code>Iterator</code> of child user entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getUsers() throws SPIException;
+
+ /**
+ * Returns suborganizations.
+ *
+ * @return <code>Iterator</code> of suborganizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getSubOrganizations() throws SPIException;
+
+ /**
+ * Returns organizations that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for organizations
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of organization objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findSubOrganizations(String aFilter, boolean aIsRecursive) throws SPIException;
+
+ /**
+ * Returns users that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for users
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of user objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findUsers(String aFilter, boolean aIsRecursive) throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/entities/OrganizationTreeProvider.java b/src/com/sun/apoc/spi/entities/OrganizationTreeProvider.java
new file mode 100644
index 0000000..7720c9f
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/OrganizationTreeProvider.java
@@ -0,0 +1,53 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.entities;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Provides access to an Organization Tree
+ * (composed of Organizations, Roles and Users)
+ *
+ */
+public interface OrganizationTreeProvider extends EntityTreeProvider {
+
+ /**
+ * Returns the root organization node of the Organization Tree
+ *
+ * @return root node
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Organization getRootOrganization() throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/entities/Role.java b/src/com/sun/apoc/spi/entities/Role.java
new file mode 100644
index 0000000..cc738bf
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/Role.java
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+
+/**
+ * Interface for a role entity.
+ *
+ */
+public interface Role extends Entity
+{
+ /**
+ * Returns a boolean indicating whether or not this role
+ * has members.
+ *
+ * @return <code>true</code> if there are members, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasMembers() throws SPIException;
+
+ /**
+ * Returns the members for this role.
+ *
+ * @return <code>Iterator</code> of member entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getMembers() throws SPIException;
+
+ /**
+ * Returns the child roles.
+ *
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getRoles() throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this role
+ * contains roles.
+ *
+ * @return <code>true</code> if there are roles, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasRoles() throws SPIException;
+
+ /**
+ * Returns the child role for this id.
+ *
+ * @param aId id string
+ * @return child <code>Role</code> with this id
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Role getRole(String aId) throws SPIException;
+}
+
diff --git a/src/com/sun/apoc/spi/entities/User.java b/src/com/sun/apoc/spi/entities/User.java
new file mode 100644
index 0000000..736bbac
--- /dev/null
+++ b/src/com/sun/apoc/spi/entities/User.java
@@ -0,0 +1,65 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.entities;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.profiles.Profile;
+
+/**
+ * Interface for a user entity.
+ *
+ */
+public interface User extends Leaf
+{
+ /**
+ * Returns the userid for this user.
+ *
+ * @return the userid
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getUserId() throws SPIException;
+
+ /**
+ * Returns the virtual user profile for this user
+ * containing the values of the user's ldap attributes
+ *
+ * @return the user profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getUserProfile() throws SPIException;
+
+}
+
diff --git a/src/com/sun/apoc/spi/environment/ConfigurationProvider.java b/src/com/sun/apoc/spi/environment/ConfigurationProvider.java
new file mode 100644
index 0000000..6218806
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/ConfigurationProvider.java
@@ -0,0 +1,45 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.environment;
+
+import java.util.Hashtable;
+
+import com.sun.apoc.spi.SPIException;
+
+public interface ConfigurationProvider {
+
+ public Hashtable loadData() throws SPIException;
+
+}
diff --git a/src/com/sun/apoc/spi/environment/EnvironmentConstants.java b/src/com/sun/apoc/spi/environment/EnvironmentConstants.java
new file mode 100644
index 0000000..6b884dd
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/EnvironmentConstants.java
@@ -0,0 +1,195 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.environment;
+
+/**
+ * Lists environmental constants.
+ */
+public interface EnvironmentConstants
+{
+ /** Character used to separate paths in URLs.
+ * value is "/" */
+ public static final String URL_SEPARATOR = "/";
+
+ /** parameter name for the hosts/domains source.
+ * value is "HOST" */
+ public static final String HOST_SOURCE = "HOST";
+ /** parameter name for the users/orgs source.
+ * value is "USER" */
+ public static final String USER_SOURCE = "USER";
+ public static final String SEPARATOR = "_" ;
+ // prefixes for the parameters
+ /** prefix to specify a parameter for the organization datasource.
+ * value is "USER_" */
+ public static final String ORGANIZATION_PREFIX = USER_SOURCE + SEPARATOR ;
+ /** prefix to specify a parameter for the domain datasource
+ * value is "HOST_" */
+ public static final String DOMAIN_PREFIX = HOST_SOURCE + SEPARATOR ;
+ /** prefix for a generic entity datasource parameter. */
+ public static final String ENTITY_PREFIX = "ENTITY_" ;
+ /** prefix to specify a parameter for the profile datasource
+ * value is "PROFILE_" */
+ public static final String PROFILE_PREFIX = "PROFILE_";
+ /** prefix to specify a parameter for the assignment datasource
+ * value is "ASSIGNMENT_" */
+ public static final String ASSIGNMENT_PREFIX = "ASSIGNMENT_";
+ // suffixes for the parameters
+ /** suffix for the parameter indicating what encoding is used for the password.
+ * value is "_ENCODING" */
+ public static final String ENCODING_SUFFIX = "_ENCODING";
+
+ // parameter names
+ /** parameter name for the username in case of an authenticated
+ * connection to the datasource.
+ * value is "SECURITY_PRINCIPAL" */
+ public static final String USER_KEY = "SECURITY_PRINCIPAL";
+ /** parameter name for the password in case of an authenticated
+ * connection to the datasource.
+ * value is "SECURITY_CREDENTIALS" */
+ public static final String CREDENTIALS_KEY = "SECURITY_CREDENTIALS";
+ /** pamarmeter name for the type of encoding used for the password
+ * in case of an authenticated connection to the datasource.
+ * value is "SECURITY_CREDENTIALS_ENCODING" */
+ public static final String CREDENTIALS_ENCODING_KEY = CREDENTIALS_KEY+ENCODING_SUFFIX;
+ /** parameter name for the URL specifying the
+ * connection to the datasource.
+ * The expected URL is of the form:
+ * &lt;protocol&gt;://&lt;username&gt;@&lt;host&gt;:&lt;port&gt;/&lt;path&gt;.
+ * value is "PROVIDER_URL" */
+ public static final String URL_KEY = "PROVIDER_URL";
+ /** parameter name for the java object providing access to the
+ * datasource.
+ * value is "PROVIDER_CLASS" */
+ public static final String CLASS_KEY = "PROVIDER_CLASS";
+ /** parameter name for the list of available sources
+ * value is "Sources" */
+ public static final String SOURCES_KEY = "Sources";
+ /** parameter name for the maximum number of results given
+ * by any search in any of the datasources.
+ * value is "SizeLimit" */
+ public static final String MAX_SEARCH_RESULTS = "SizeLimit";
+
+ // parameter values
+ /** indicates that the password has been scrambled.
+ * value is "scramble".
+ */
+ public static final String SCRAMBLE_ENCODING = "scramble";
+ /** indicates that the password appears in clear text.
+ * value is "none".
+ */
+ public static final String NONE_ENCODING = "none";
+
+ // protocol defining the URLs
+ /** protocol to define a LDAP URL.
+ * The expected LDAP URL is of the form:
+ * ldap://&lt;username&gt;@&lt;host&gt;:&lt;port&gt;/&lt;ldap_baseDN&gt;
+ */
+ public static final String LDAP_URL_PROTOCOL = "ldap";
+
+ /** protocol to define a secure LDAP URL.
+ * The expected LDAP URL is of the form:
+ * ldaps://&lt;username&gt;@&lt;host&gt;:&lt;port&gt;/&lt;ldap_baseDN&gt;
+ */
+ public static final String LDAPS_URL_PROTOCOL = "ldaps";
+
+ /** protocol to define a file URL.
+ * The expected file URL is of the form:
+ * file:///&lt;path&gt;
+ */
+ public static final String FILE_URL_PROTOCOL = "file";
+
+ /** protocol to define an HTTP URL.
+ * The expected file URL is of the form:
+ * http://&lt;host&gt;[:]&lt;port&gt;/&lt;path&gt;
+ */
+ public static final String HTTP_URL_PROTOCOL = "http";
+
+ /** protocol to define an HTTPS URL.
+ * The expected file URL is of the form:
+ * https://&lt;host&gt;[:]&lt;port&gt;/&lt;path&gt;
+ */
+ public static final String HTTPS_URL_PROTOCOL = "https";
+
+
+ // Ldap specific keys
+ /** Ldap specific prefix to specify a parameter
+ * for the Ldap metaconfiguration datasource.
+ * value is "LDAP_META_CONF_"*/
+ public static final String LDAP_META_CONF_PREFIX = "LDAP_META_CONF_";
+ /** Ldap specific key for AuthDn.
+ * value is "AuthDn"*/
+ public static final String LDAP_AUTH_USER_KEY = "AuthDn" ;
+ /** Ldap specific key for authentication password.
+ * value is "Password"*/
+ public static final String LDAP_AUTH_PASSWORD_KEY = "Password" ;
+ /** Ldap specific key for the encoding type for authentication password.
+ * value is "Password_ENCODING"*/
+ public static final String LDAP_AUTH_PWD_ENCODING_KEY = LDAP_AUTH_PASSWORD_KEY+ENCODING_SUFFIX ;
+ /** Ldap specific key for authentication type.
+ * value is "AuthType"*/
+ public static final String LDAP_AUTH_TYPE_KEY = "AuthType";
+ /** Ldap specific key for connection creation timeout.
+ * value is "ConnectTimeout" */
+ public static final String LDAP_TIMEOUT_KEY = "ConnectTimeout";
+ /** Ldap specific key for authentication callback handler.
+ * value is "AuthCallbackHandler" */
+ public static final String LDAP_AUTH_CBH = "AuthCallbackHandler";
+
+ // Ldap specific values
+ /** Ldap specific value for Anonymous authentication type.
+ * value is "Anonymous" */
+ public static final String LDAP_AUTH_TYPE_ANONYMOUS = "Anonymous";
+ /** Ldap specific value for GSSAPI authentication type.
+ * value is "GSSAPI" */
+ public static final String LDAP_AUTH_TYPE_GSSAPI = "GSSAPI";
+ /** Ldap specific value for default connection timeout.
+ * value is 1 */
+ public static final int LDAP_DEFAULT_TIMEOUT = 1;
+ /** Ldap specific value for default server.
+ * value is "localhost" */
+ public static final String LDAP_DEFAULT_SERVER = "localhost";
+ /** Ldap specific value for default port.
+ * value is 389 */
+ public static final int LDAP_DEFAULT_PORT = 389;
+ /** Ldap specific value for anonymous authentication user name .
+ * value is "Anonymous" */
+ public static final String LDAP_USER_ANONYMOUS = "Anonymous";
+
+ // File specific constants
+ /** Name of the Ldap Organization Mapping file.
+ * value is "OrganizationMapping.properties" */
+ public static String ORG_MAP_FILE = "OrganizationMapping.properties";
+}
diff --git a/src/com/sun/apoc/spi/environment/EnvironmentException.java b/src/com/sun/apoc/spi/environment/EnvironmentException.java
new file mode 100644
index 0000000..900337b
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/EnvironmentException.java
@@ -0,0 +1,55 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.environment;
+
+import com.sun.apoc.spi.SPIException;
+
+public class EnvironmentException extends SPIException {
+
+ public EnvironmentException () {
+ super();
+ }
+
+ public EnvironmentException (String messageKey,
+ Object[] messageParams) {
+ super(messageKey, messageParams);
+ }
+
+ public EnvironmentException (String messageKey,
+ Object[] messageParams,
+ Throwable cause) {
+ super(messageKey, messageParams, cause);
+ }
+}
diff --git a/src/com/sun/apoc/spi/environment/EnvironmentMgr.java b/src/com/sun/apoc/spi/environment/EnvironmentMgr.java
new file mode 100644
index 0000000..e4a773d
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/EnvironmentMgr.java
@@ -0,0 +1,726 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.environment;
+
+import com.sun.apoc.spi.AssignmentProvider;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.EntityTreeProvider;
+import com.sun.apoc.spi.profiles.ProfileProvider;
+
+/**
+ * Handles the environmental information.
+ *
+ */
+public class EnvironmentMgr
+{
+ /* old parameter names (from APOC 1.0)*/
+ public static final String SERVER_KEY = "Server";
+ public static final String PORT_KEY = "Port";
+ public static final String BASE_DN_KEY = "BaseDn";
+ public static final String TYPE_KEY = "DataStoreType";
+ public static final String LDAP_TYPE = "LDAP";
+
+ /* table containing environment settings */
+ protected Hashtable mEnvironment;
+
+ protected static HashSet sLdapProtocols = new HashSet();
+ protected static HashSet sFileProtocols = new HashSet();
+
+ private Hashtable mConnections = new Hashtable();
+
+ /**
+ * Static constructor, just puts the accepted protocol strings in the
+ * appropriate scheme sets.
+ */
+ static {
+ sLdapProtocols.add(EnvironmentConstants.LDAP_URL_PROTOCOL);
+ sLdapProtocols.add(EnvironmentConstants.LDAPS_URL_PROTOCOL);
+ sFileProtocols.add(EnvironmentConstants.FILE_URL_PROTOCOL);
+ sFileProtocols.add(EnvironmentConstants.HTTP_URL_PROTOCOL);
+ sFileProtocols.add(EnvironmentConstants.HTTPS_URL_PROTOCOL);
+ }
+ /**
+ * Constructor for class.
+ *
+ * @param aEnvironment table of environmental information
+ */
+ public EnvironmentMgr(Hashtable aEnvironment) {
+ mEnvironment = aEnvironment;
+ translateOldParameters() ;
+ }
+
+ public void translateOldParameters() {
+ if ( (this.getOrganizationURLs().length == 0)
+ && (this.getDomainURLs().length == 0)
+ && (this.getProfileURLs().length == 0)
+ && (this.getAssignmentURLs().length == 0) ) {
+ String type = (String)mEnvironment.get(TYPE_KEY);
+ if ( (type == null) || (type.length() == 0) ) {
+ type = LDAP_TYPE;
+ }
+ if (type.equals(LDAP_TYPE)) {
+ String server = (String)mEnvironment.get(SERVER_KEY);
+ boolean noServer = (server == null)
+ || (server.length() == 0);
+ String basedn = (String)mEnvironment.get(BASE_DN_KEY);
+ boolean noBasedn = (basedn == null)
+ || (basedn.length() == 0);
+ if (!noServer && !noBasedn) {
+ StringBuffer url = new StringBuffer(
+ EnvironmentConstants.LDAP_URL_PROTOCOL);
+ url.append("://").append(server);
+ String port = (String)mEnvironment.get(PORT_KEY);
+ boolean noPort = (port == null)
+ || (port.length() == 0);
+ if (!noPort) {
+ url.append(":").append(port);
+ }
+ url.append("/").append(basedn);
+ mEnvironment.put(EnvironmentConstants.URL_KEY,
+ url.toString());
+ }
+ }
+ }
+ }
+
+ /**
+ * Check the validity of the configuration data provided in the
+ * environment table.
+ *
+ * @throws SPIException if data missing
+ * or value not appropriate
+ * @throws MissingParameterException
+ * @throws InvalidParameterException
+ */
+ public void checkEnvironment( ) throws SPIException {
+ // mandatory parameters
+ /* if (this.getOrganizationURLs().length == 0) {
+ throw new MissingParameterException(
+ "organization "+EnvironmentConstants.URL_KEY);
+ }
+ if (this.getDomainURLs().length == 0) {
+ throw new MissingParameterException(
+ "domain "+EnvironmentConstants.URL_KEY);
+ }
+ if (this.getProfileURLs().length == 0) {
+ throw new MissingParameterException(
+ "profile "+EnvironmentConstants.URL_KEY);
+ }
+ if (this.getAssignmentURLs().length == 0) {
+ throw new MissingParameterException(
+ "assignment "+EnvironmentConstants.URL_KEY);
+ }*/
+ }
+
+ /**
+ * Returns a copy of the environment table, excluding the user name and credentials.
+ *
+ * @return <code>Hashtable</code> containing the environment settings, excluding
+ * the user name and credentials
+ */
+ public Hashtable getEnvironment() {
+ return mEnvironment;
+ }
+
+ /**
+ * Accessor to a String parameter in the environment table
+ *
+ * @param paramName the name of the parameter to return
+ * @return the String value of that parameter
+ */
+ public String getStringParam(String paramName) {
+ return (String)mEnvironment.get(paramName);
+ }
+
+ /**
+ * Accessor to a String parameter in the environment table
+ * depending on its prefix
+ *
+ * @param prefix the prefix to append at the beginning
+ * of the parameter name
+ * @param paramName the name of the parameter to return
+ * @return the String value of that parameter
+ */
+ protected String getParam(String prefix, String paramName) {
+ String paramValue = null;
+ if (prefix != null) {
+ paramValue = getStringParam(prefix + paramName);
+ }
+ if (paramValue == null) {
+ paramValue = getStringParam(paramName);
+ }
+ return paramValue;
+ }
+
+ /**
+ * Accessor to a String parameter in the environment table
+ * depending on its prefix
+ *
+ * @param aEntityPrefix the prefix denoting the entity type
+ * of the parameter
+ * @param aProviderPrefix the prefix denoting the provider type
+ * of the parameter
+ * @param paramName the name of the parameter to return
+ * @return the String value of that parameter
+ */
+ protected String getParam(String aEntityPrefix, String aProviderPrefix, String paramName) {
+ String paramValue = null;
+ if (aEntityPrefix != null && aProviderPrefix!= null) {
+ paramValue = getStringParam(aEntityPrefix + aProviderPrefix + paramName);
+ }
+ if (paramValue == null) {
+ paramValue = getStringParam(aProviderPrefix + paramName);
+ }
+ if (paramValue == null) {
+ paramValue = getStringParam(paramName);
+ }
+ return paramValue;
+ }
+
+ /**
+ * Splits a String composed of URLs separated by white spaces
+ * into a array of String
+ *
+ * @param urlString the list of URLs
+ * @return an array of URLs
+ */
+ protected String[] getURLList(String urlString) {
+ String[] urls = new String[0];
+ if (urlString != null) {
+ urls = urlString.split("\\s");
+ }
+ return urls;
+ }
+
+ /**
+ * gets the value of a parameter representing a int.
+ *
+ * @param stringValue the string value of the parametrer
+ * @param defaultValue the default value for that parameter
+ * @return the int value of that parameter
+ * or the defaultValue if there is an error
+ */
+ protected int getIntParamFromString(String stringValue,
+ int defaultValue) {
+ int intValue = defaultValue;
+ try {
+ intValue = Integer.parseInt(stringValue);
+ }
+ catch (Exception e) {}
+ return intValue;
+ }
+
+ /**
+ * gets the password parameter value for the given prefix
+ * and password name
+ *
+ * @param prefix prefix to search password param for
+ * @param paramName name of the password parameter
+ * @return parameter value for the given prefix
+ * and parameter name
+ */
+ protected char[] getPasswordParam(String prefix, String paramName) {
+ Object paramValue = null;
+ char[] credentials = null;
+ paramValue = mEnvironment.get(prefix+paramName);
+ if (paramValue == null) {
+ paramValue = mEnvironment.get(paramName);
+ }
+ if (paramValue != null) {
+ if (paramValue instanceof String) {
+ credentials = ((String)paramValue).toCharArray();
+ }
+ else {
+ try {
+ credentials = (char[])paramValue;
+ } catch (ClassCastException cce) {
+ credentials = null;
+ }
+ }
+ }
+ String passwordEncoding = getStringParam(
+ prefix+paramName+EnvironmentConstants.ENCODING_SUFFIX);
+ if (passwordEncoding == null) {
+ passwordEncoding = getStringParam(
+ paramName+EnvironmentConstants.ENCODING_SUFFIX);
+ }
+ if ((passwordEncoding != null)
+ && passwordEncoding.equals(EnvironmentConstants.SCRAMBLE_ENCODING)) {
+ }
+ return credentials;
+ }
+
+ /**
+ * gets the value of the user from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the user extracted from the URL
+ * or null if error
+ */
+ public static String getUserFromURL(String stringURL) {
+ String username = null;
+ try {
+ username = new URI(stringURL).getUserInfo();
+ } catch (Exception e) {}
+ return username;
+ }
+
+ /**
+ * gets the value the protocol from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the protocol extracted from the URL
+ * or null if error
+ */
+ public static String getProtocolFromURL(String stringURL) {
+ String protocol = null;
+ try {
+ protocol = new URI(stringURL).getScheme();
+ } catch (Exception e) {}
+ return protocol;
+ }
+
+ /**
+ * gets the value of the host from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the host extracted from the URL
+ * or null if error
+ */
+ public static String getHostFromURL(String stringURL) {
+ String host = null;
+ try {
+ host = new URI(stringURL).getHost();
+ } catch (Exception e) {}
+ return host;
+ }
+
+ /**
+ * gets the value of the port from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the port extracted from the URL
+ * or -1 if error occurs
+ */
+ public static int getPortFromURL(String stringURL) {
+ int port = -1;
+ try {
+ URI url = new URI(stringURL);
+ port = url.getPort();
+ } catch (Exception e) {}
+ return port;
+ }
+
+ /**
+ * gets the value of the path from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the path extracted from the URL
+ * or null if error
+ */
+ public static String getPathFromURL(String stringURL) {
+ String path = null;
+ try {
+ path = new URI(stringURL).getPath();
+ } catch (Exception e) {}
+ return path;
+ }
+
+ /**
+ * Accessor for the list of URLs applicable
+ * to the organization datasource
+ *
+ * @return the URLs for the organization datasource
+ */
+ public String[] getOrganizationURLs() {
+ String urls = getParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.URL_KEY);
+ return getURLList(urls);
+ }
+
+ /**
+ * Accessor for the list of URLs applicable
+ * to the domain datasource
+ *
+ * @return the URLs for the domain datasource
+ */
+ public String[] getDomainURLs() {
+ String urls = getParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.URL_KEY);
+ return getURLList(urls);
+ }
+
+ /**
+ * Accessor for the list of URLs applicable
+ * to the profile datasource
+ *
+ * @return the URLs for the profile datasource
+ */
+ public String[] getProfileURLs() {
+ String urls = getParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.URL_KEY);
+ return getURLList(urls);
+ }
+
+ /**
+ * Accessor for the list of URLs applicable
+ * to the assignment datasource
+ *
+ * @return the URLs for the assignment datasource
+ */
+ public String[] getAssignmentURLs() {
+ String urls = getParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.URL_KEY);
+ return getURLList(urls);
+ }
+
+ /**
+ * Accessor for the list of URLs applicable
+ * to the entity datasource
+ *
+ * @return the URLs for the entity datasource
+ */
+ public String[] getProviderURLs(String aEntityPrefix, String aProviderPrefix) {
+ String urls = getParam(aEntityPrefix,
+ aProviderPrefix,
+ EnvironmentConstants.URL_KEY);
+ return getURLList(urls);
+ }
+
+ /**
+ * Accessor for the list of URLs applicable
+ * to the entity datasource
+ *
+ * @return the URLs for the entity datasource
+ */
+ public String getProviderClass(String aEntityPrefix, String aProviderPrefix) {
+ return getParam(aEntityPrefix,
+ aProviderPrefix,
+ EnvironmentConstants.CLASS_KEY);
+ }
+
+ public String[] getProviderURLs(String aName, Class aProviderClass) {
+ String aProviderPrefix = null;
+ if (aProviderClass == EntityTreeProvider.class) {
+ aProviderPrefix = "";
+ } else if (aProviderClass == AssignmentProvider.class) {
+ aProviderPrefix = EnvironmentConstants.ASSIGNMENT_PREFIX;
+ } else if (aProviderClass == ProfileProvider.class) {
+ aProviderPrefix = EnvironmentConstants.PROFILE_PREFIX;
+ }
+ aName = aName + EnvironmentConstants.SEPARATOR ;
+ return getProviderURLs(aName, aProviderPrefix);
+ }
+
+ public String getProviderClass(String aName, Class aProviderClass) {
+ String aProviderPrefix = null;
+ if (aProviderClass == EntityTreeProvider.class) {
+ aProviderPrefix = "";
+ } else if (aProviderClass == AssignmentProvider.class) {
+ aProviderPrefix = EnvironmentConstants.ASSIGNMENT_PREFIX;
+ } else if (aProviderClass == ProfileProvider.class) {
+ aProviderPrefix = EnvironmentConstants.PROFILE_PREFIX;
+ }
+ aName = aName + EnvironmentConstants.SEPARATOR ;
+ return getProviderClass(aName, aProviderPrefix);
+ }
+
+ public String[] getSources() {
+ return EnvironmentMgr.getSources(mEnvironment) ;
+ }
+
+ private static final String [] DEFAULT_SOURCES = {
+ EnvironmentConstants.HOST_SOURCE, EnvironmentConstants.USER_SOURCE
+ } ;
+
+ public static String [] getSources(Hashtable aEnvironment) {
+ String sourcesList =
+ (String) aEnvironment.get(EnvironmentConstants.SOURCES_KEY);
+ if (sourcesList == null) {
+ return DEFAULT_SOURCES ;
+ } else {
+ return sourcesList.split(",");
+ }
+ }
+
+ /**
+ * Accessor for the credentials applicable
+ * to the organization datasource
+ *
+ * @return the credentials for the organization datasource
+ */
+ public char[] getOrganizationCredentials() {
+ return getPasswordParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.CREDENTIALS_KEY);
+ }
+
+ /**
+ * Accessor for the credentials applicable
+ * to the domain datasource
+ *
+ * @return the credentials for the domain datasource
+ */
+ public char[] getDomainCredentials() {
+ return getPasswordParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.CREDENTIALS_KEY);
+ }
+
+ /**
+ * Accessor for the credentials applicable
+ * to the profile datasource
+ *
+ * @return the credentials for the profile datasource
+ */
+ public char[] getProfileCredentials() {
+ return getPasswordParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.CREDENTIALS_KEY);
+ }
+
+ /**
+ * Accessor for the credentials applicable
+ * to the assignment datasource
+ *
+ * @return the credentials for the assignment datasource
+ */
+ public char[] getAssignmentCredentials() {
+ return getPasswordParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.CREDENTIALS_KEY);
+ }
+
+ /**
+ * Accessor for the provider class applicable
+ * to the organization datasource
+ *
+ * @return the provider class for the
+ * organization datasource
+ */
+ public String getOrganizationClass() {
+ return getParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.CLASS_KEY);
+ }
+
+ /**
+ * Accessor for the provider applicable
+ * to the domain datasource
+ *
+ * @return the provider class for the
+ * organization datasource
+ */
+ public String getDomainClass() {
+ return getParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.CLASS_KEY);
+ }
+
+ /**
+ * Accessor for the provider applicable to the profile datasource
+ *
+ * @return the provider class for the
+ * organization datasource
+ */
+ public String getProfileClass() {
+ return getParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.CLASS_KEY);
+ }
+
+ /**
+ * Accessor for the provider applicable
+ * to the assignment datasource
+ *
+ * @return the provider class for the
+ * organization datasource
+ */
+ public String getAssignmentClass() {
+ return getParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.CLASS_KEY);
+ }
+
+ /**
+ * Accessor for the user applicable
+ * to the organization datasource
+ *
+ * @param url the url where the username can be declared
+ * @return the user for the organization datasource
+ */
+ public String getOrganizationUser(String url) {
+ String username = null;
+ username = getUserFromURL(url);
+ if (username == null) {
+ username = getParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.USER_KEY);
+ }
+ return username;
+ }
+
+ /**
+ * Accessor for the user applicable
+ * to the domain datasource
+ *
+ * @param url the url where the username can be declared
+ * @return the user for the domain datasource
+ */
+ public String getDomainUser(String url) {
+ String username = null;
+ if (url != null) {
+ username = getUserFromURL(url);
+ }
+ if (username == null) {
+ username = getParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.USER_KEY);
+ }
+ return username;
+ }
+
+ /**
+ * Accessor for the user applicable
+ * to the profile datasource
+ *
+ * @param url the url where the username can be declared
+ * @return the user for the Profile datasource
+ */
+ public String getProfileUser(String url) {
+ String username = null;
+ if (url != null) {
+ username = getUserFromURL(url);
+ }
+ if (username == null) {
+ username = getParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.USER_KEY);
+ }
+ return username;
+ }
+
+ /**
+ * Accessor for the user applicable
+ * to the assignment datasource
+ *
+ * @param url the url where the username can be declared
+ * @return the user for the assignment datasource
+ */
+ public String getAssignmentUser(String url) {
+ String username = null;
+ if (url != null) {
+ username = getUserFromURL(url);
+ }
+ if (username == null) {
+ username = getParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.USER_KEY);
+ }
+ return username;
+ }
+
+ /**
+ * Indicates if the submitted protocol is a protocol
+ * for an Ldap connection
+ *
+ * @param protocol a String identifying the protocol
+ * @return true if protocol is ldap or ldaps
+ */
+ public static boolean isLdapProtocol(String protocol) {
+ return sLdapProtocols.contains(protocol);
+ }
+
+ /**
+ * Indicates if the submitted protocol is a protocol
+ * for an File or HTTP connection
+ *
+ * @param protocol a String identifying the protocol
+ * @return true if protocol is file, http or https
+ */
+ public static boolean isFileProtocol(String protocol) {
+ return sFileProtocols.contains(protocol);
+ }
+
+ /**
+ * returns a String listing all the supported connection protocols.
+ * This list is to be used in error messages for example.
+ * @return list of supported protocols
+ */
+ public static String getSupportedProtocolsString() {
+ StringBuffer protocolsString = new StringBuffer("{");
+ Iterator iterLdapProtocols = sLdapProtocols.iterator();
+ while (iterLdapProtocols.hasNext()) {
+ protocolsString.append((String)iterLdapProtocols.next()).append(",");
+ }
+ Iterator iterFileProtocols = sFileProtocols.iterator();
+ while (iterFileProtocols.hasNext()) {
+ protocolsString.append((String)iterFileProtocols.next()).append(",");
+ }
+ if (protocolsString.lastIndexOf(",") == (protocolsString.length()-1)) {
+ protocolsString.delete(protocolsString.length()-1, protocolsString.length());
+ }
+ protocolsString.append("}");
+ return protocolsString.toString();
+ }
+
+ /**
+ * gets the object stored under the key url
+ * and managing the connection to that url
+ *
+ * @param stringURL the string representing the URL
+ * for the connection
+ * @return an object managing the connection
+ * or null if one does not exist
+ */
+ public synchronized Object getConnectionHandler(String stringURL) {
+ Object connection = null;
+ if (stringURL != null) {
+ connection = mConnections.get(stringURL);
+ }
+ return connection;
+ }
+
+ /**
+ * stores a connection handler under the key url
+ *
+ * @param stringURL the string representing the URL
+ * @param connection the object managing the connection
+ */
+ public synchronized void setConnectionHandler(String stringURL, Object connection) {
+ if (stringURL != null) {
+ if (connection == null) {
+ mConnections.remove(stringURL);
+ }
+ else {
+ mConnections.put(stringURL, connection);
+ }
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/environment/InvalidParameterException.java b/src/com/sun/apoc/spi/environment/InvalidParameterException.java
new file mode 100644
index 0000000..52c667d
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/InvalidParameterException.java
@@ -0,0 +1,71 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.environment;
+
+public class InvalidParameterException extends ParameterException {
+
+ private static final String PARAMETER_INVALID_KEY =
+ "error.spi.environment.parameter.invalid";
+ private static final String PARAMETER_INVALID_WITH_RANGE_KEY =
+ "error.spi.environment.parameter.invalid.range";
+
+ protected String mParamValue = null;
+
+ public InvalidParameterException () {
+ super();
+ }
+
+ public InvalidParameterException (String paramName,
+ String paramValue) {
+ super();
+ mParamName = paramName;
+ mParamValue = paramValue;
+ mMessageKey = PARAMETER_INVALID_KEY;
+ mMessageParams = new Object[]{mParamName, mParamValue};
+ }
+
+ public InvalidParameterException (String paramName,
+ String paramValue,
+ String valueRange) {
+ super();
+ mParamName = paramName;
+ mParamValue = paramValue;
+ mValueRange = valueRange;
+ mMessageKey = PARAMETER_INVALID_WITH_RANGE_KEY;
+ mMessageParams = new Object[]{mParamName, mParamValue, mValueRange};
+ }
+
+ public String getValue() {return mParamValue;}
+}
diff --git a/src/com/sun/apoc/spi/environment/MissingParameterException.java b/src/com/sun/apoc/spi/environment/MissingParameterException.java
new file mode 100644
index 0000000..bbad6df
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/MissingParameterException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.environment;
+
+public class MissingParameterException extends ParameterException {
+
+ private static final String PARAMETER_MISSING_KEY =
+ "error.spi.environment.parameter.missing";
+ private static final String PARAMETER_MISSING_WITH_RANGE_KEY =
+ "error.spi.environment.parameter.missing.range";
+
+ public MissingParameterException () {
+ super();
+ }
+
+ public MissingParameterException (String paramName) {
+ super();
+ mParamName = paramName;
+ mMessageKey = PARAMETER_MISSING_KEY;
+ mMessageParams = new Object[]{mParamName};
+ }
+
+ public MissingParameterException (String paramName, String valueRange) {
+ super();
+ mParamName = paramName;
+ mValueRange = valueRange;
+ mMessageKey = PARAMETER_MISSING_WITH_RANGE_KEY;
+ mMessageParams = new Object[]{mParamName, mValueRange};
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/environment/ParameterException.java b/src/com/sun/apoc/spi/environment/ParameterException.java
new file mode 100644
index 0000000..ad7b938
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/ParameterException.java
@@ -0,0 +1,68 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.environment;
+
+public class ParameterException extends EnvironmentException {
+
+ private static final String PARAMETER_KEY =
+ "error.spi.environment.parameter";
+ private static final String PARAMETER_WITH_RANGE_KEY =
+ "error.spi.environment.parameter.range";
+
+ protected String mParamName = null;
+ protected String mValueRange = null;
+
+ public ParameterException () {
+ super();
+ }
+
+ public ParameterException (String paramName) {
+ super();
+ mParamName = paramName;
+ mMessageKey = PARAMETER_KEY;
+ mMessageParams = new Object[]{mParamName};
+ }
+
+ public ParameterException (String paramName, String valueRange) {
+ super();
+ mParamName = paramName;
+ mValueRange = valueRange;
+ mMessageKey = PARAMETER_WITH_RANGE_KEY;
+ mMessageParams = new Object[]{mParamName, mValueRange};
+ }
+
+ public String getName() {return mParamName;}
+ public String getAllowedValueRange() {return mValueRange;}
+}
diff --git a/src/com/sun/apoc/spi/environment/RemoteEnvironmentException.java b/src/com/sun/apoc/spi/environment/RemoteEnvironmentException.java
new file mode 100644
index 0000000..4b94fb4
--- /dev/null
+++ b/src/com/sun/apoc/spi/environment/RemoteEnvironmentException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.environment;
+
+public class RemoteEnvironmentException extends EnvironmentException {
+
+ public static final String FILE_CONF_KEY =
+ "error.spi.environment.remote.file";
+ public static final String LDAP_CONF_KEY =
+ "error.spi.environment.remote.ldap";
+ public static final String INVALID_LDAP_CONF_KEY =
+ "error.spi.environment.remote.ldap.invalid";
+ public static final String INVALID_META_CONF_KEY =
+ "error.spi.environment.remote.metaconf.invalid";
+
+ public RemoteEnvironmentException () {
+ super();
+ }
+
+ public RemoteEnvironmentException (String messageKey,
+ Object[] messageParams) {
+ super(messageKey, messageParams);
+ }
+
+ public RemoteEnvironmentException (String messageKey,
+ Object[] messageParams,
+ Throwable cause) {
+ super(messageKey, messageParams, cause);
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/file/FileProviderFactory.java b/src/com/sun/apoc/spi/file/FileProviderFactory.java
new file mode 100644
index 0000000..9223fba
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/FileProviderFactory.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file;
+
+import com.sun.apoc.spi.AssignmentProvider;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.Provider;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.EntityTreeProvider;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.file.assignments.FileAssignmentProvider;
+import com.sun.apoc.spi.file.entities.FileDomainProvider;
+import com.sun.apoc.spi.file.entities.FileOrganizationProvider;
+import com.sun.apoc.spi.file.profiles.FileProfileProvider;
+import com.sun.apoc.spi.profiles.ProfileProvider;
+
+/**
+ * Class for providing File-type Providers.
+ */
+public class FileProviderFactory {
+
+ public FileProviderFactory(String url, Class aProviderClass, PolicySource aSource) {
+ }
+
+ /**
+ * Returns the requested type of <code>Provider</code> object .
+ *
+ * @param url the url specifying the provider data source
+ * @param aProviderClass the type of <code>Provider</code> object
+ * @param aPolicySource the <code>PolicySource</code> that owns these providers
+ * @return <code>Provider</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ static public Provider get(String url, Class aProviderClass, PolicySource aPolicySource) throws SPIException {
+ Provider provider = null;
+ String sEntityType = aPolicySource.getName();
+ if (aProviderClass == EntityTreeProvider.class) {
+ if (sEntityType.equals(EnvironmentConstants.HOST_SOURCE)) {
+ provider = new FileDomainProvider(aPolicySource, url);
+ } else if (sEntityType.equals(EnvironmentConstants.USER_SOURCE)) {
+ provider = new FileOrganizationProvider(aPolicySource, url);
+ }
+ } else if (aProviderClass == AssignmentProvider.class) {
+ provider = new FileAssignmentProvider(aPolicySource, url);
+ } else if (aProviderClass == ProfileProvider.class) {
+ provider = new FileProfileProvider(aPolicySource, url);
+ }
+ return provider;
+ }
+}
+
diff --git a/src/com/sun/apoc/spi/file/assignments/FileAssignmentProvider.java b/src/com/sun/apoc/spi/file/assignments/FileAssignmentProvider.java
new file mode 100644
index 0000000..fd2d209
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/assignments/FileAssignmentProvider.java
@@ -0,0 +1,334 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.assignments;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.sun.apoc.spi.AbstractAssignmentProvider;
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.IllegalWriteException;
+import com.sun.apoc.spi.OpenConnectionException;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.environment.InvalidParameterException;
+import com.sun.apoc.spi.environment.MissingParameterException;
+import com.sun.apoc.spi.profiles.InvalidProfileException;
+import com.sun.apoc.spi.profiles.Profile;
+
+public class FileAssignmentProvider extends AbstractAssignmentProvider
+{
+ private static final String DEFAULT_ASSIGN_CONTAINER = "assignments";
+ private static final String DEFAULT_EXTENSION = ".dat";
+ private URL mLocation;
+ private Map mEntitiesAssign;
+ private Map mProfilesAssign;
+ private boolean mDataIsLoaded;
+ private boolean mLoadingData;
+ private boolean mReadOnly;
+ private boolean mRemote;
+ private File mFile;
+
+ public FileAssignmentProvider( PolicySource aPolicySource, String aUrl ) throws SPIException {
+ StringBuffer location;
+
+ if ( (aUrl == null) || (aUrl.length() == 0)) {
+ throw new MissingParameterException("domain "+EnvironmentConstants.URL_KEY);
+ }
+ mPolicySource = aPolicySource;
+ location = new StringBuffer(aUrl);
+ if ( location.charAt(location.length() - 1) != '/' ) {
+ location.append('/');
+ }
+ if(!(location.toString().endsWith(DEFAULT_ASSIGN_CONTAINER + "/"))) {
+ location.append(DEFAULT_ASSIGN_CONTAINER).append('/');
+ }
+
+ try {
+ mLocation = new URL( location.toString() );
+ if ( mLocation.getProtocol().equals(EnvironmentConstants.FILE_URL_PROTOCOL) ) {
+ mRemote = false;
+ } else {
+ mRemote = true;
+ }
+ } catch (MalformedURLException e) {
+ throw new InvalidParameterException(
+ "assignment "+EnvironmentConstants.URL_KEY,
+ location.toString());
+ }
+ }
+
+
+ public Iterator getEntitiesAssignedToProfile(Profile aProfile ) throws SPIException {
+ List entityList;
+ String[] fileList;
+ HashSet profileIDs;
+ String entityId;
+ int indx;
+
+ if ( mRemote ) {
+ throw new UnsupportedOperationException();
+ }
+ entityList = new LinkedList();
+ // read list of files
+ fileList = mFile.list();
+ for ( int i = 0; i< fileList.length; i++ ) {
+ try {
+ indx = fileList[i].indexOf(DEFAULT_EXTENSION);
+ if ( indx != -1 ) {
+ entityId = fileList[i].substring(0, indx).replace('+', ' ');
+ profileIDs = readAssignedProfileIDs( entityId );
+ if ( profileIDs.contains( aProfile.getId() ) ) {
+ entityList.add( getEntity( entityId ) );
+ }
+ }
+ } catch ( IOException e ) {
+ // keep reading next file
+ }
+ }
+
+ return entityList.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.AssignmentProvider#assignProfile(com.sun.apoc.spi.entities.Entity, com.sun.apoc.spi.profiles.Profile)
+ */
+ public void assignProfileToEntity(Entity aEntity, Profile aProfile) throws SPIException {
+ HashSet profileIDs = null;
+
+ try {
+ profileIDs = readAssignedProfileIDs( aEntity.getId() );
+ } catch ( SPIException e ) {
+ profileIDs = new HashSet();
+ } catch ( IOException e ) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+ profileIDs.add( aProfile.getId() );
+ writeAssignments( aEntity.getId(), profileIDs );
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.AssignmentProvider#unassignProfile(com.sun.apoc.spi.entities.Entity, com.sun.apoc.spi.profiles.Profile)
+ */
+ public void unassignProfile(Entity aEntity, Profile aProfile) throws SPIException {
+ HashSet profileIDs = null;
+ String profileId;
+
+ profileId = aProfile.getId();
+
+ // it the entity does not exists we get an exception here. It's ok can not unassign from an entity
+ // who doesn't have profiles assigned
+ try {
+ profileIDs = readAssignedProfileIDs( aEntity.getId() );
+ } catch ( SPIException e ) {
+ // if the entity does not exists we get an exception here.
+ // It's ok. Can not unassign from an entity
+ // who doesn't have profiles assigned
+ profileIDs = new HashSet();
+ } catch ( IOException e ) {
+ throw new InvalidProfileException(
+ InvalidProfileException.NO_EXIST_PROFILE_KEY,
+ profileId, e);
+ }
+ if ( profileIDs.contains( profileId ) ) {
+ profileIDs.remove( profileId );
+ } else {
+ throw new InvalidProfileException(
+ InvalidProfileException.NO_EXIST_PROFILE_KEY,
+ profileId);
+ }
+
+ writeAssignments( aEntity.getId(), profileIDs );
+ }
+
+ public Iterator getProfilesAssignedToEntity( Entity aEntity ) throws SPIException {
+ HashSet profileIDs;
+ List profiles;
+ try {
+ profileIDs = readAssignedProfileIDs( aEntity.getId() );
+ } catch ( SPIException e ) {
+ profileIDs = new HashSet();
+ } catch (IOException e) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+
+ profiles = new LinkedList();
+
+ Iterator it = profileIDs.iterator();
+
+ while ( it.hasNext() ) {
+ profiles.add(mPolicySource.getProfileProvider().getProfile( (String)it.next() ));
+ }
+ return profiles.iterator();
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.AssignmentProvider#open()
+ */
+ public void open() throws SPIException {
+ if ( mRemote ) {
+ try {
+ mLocation.openStream();
+ } catch (IOException e) {
+ // could not connect to the repository
+ throw new OpenConnectionException(
+ mLocation.toString(), e);
+ }
+ } else {
+ try {
+ mFile = new File( new URI( mLocation.toString() ) );
+ if ( !mFile.exists() ) {
+ throw new IllegalReadException(IllegalReadException.FILE_NAME_READ_KEY,mFile.getAbsolutePath());
+ } else if ( !mFile.isDirectory() ) {
+ throw new InvalidParameterException(
+ "profile "+EnvironmentConstants.URL_KEY,
+ mLocation.toString());
+ }
+
+ if ( mFile.canWrite() ) {
+ mReadOnly = false;
+ } else {
+ mReadOnly = true;
+ }
+ } catch ( URISyntaxException e ){
+ throw new InvalidParameterException(
+ "assignment "+EnvironmentConstants.URL_KEY,
+ mLocation.toString());
+ }
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.AssignmentProvider#close()
+ */
+ public void close() throws SPIException {
+ // Nothing to do
+
+ }
+
+ private HashSet readAssignedProfileIDs( String aEntityId ) throws MalformedURLException, IOException, SPIException {
+ BufferedReader reader = null;
+ URL entityAssignments;
+ HashSet profileIDs;
+ String profileId;
+ StringBuffer fileName;
+
+ profileIDs = new HashSet();
+ try {
+ if ( mRemote ) {
+ fileName = new StringBuffer(URLEncoder.encode(aEntityId,System.getProperty("file.encoding")));
+ fileName.append(DEFAULT_EXTENSION);
+ entityAssignments = new URL( mLocation, fileName.toString() );
+ reader = new BufferedReader( new InputStreamReader( entityAssignments.openStream() ) );
+ } else {
+ fileName = new StringBuffer( aEntityId.replace(' ', '+') );
+ fileName.append(DEFAULT_EXTENSION);
+ reader = new BufferedReader( new FileReader( new File( mFile, fileName.toString() ) ) );
+ }
+ } catch ( MalformedURLException e ) {
+ throw e;
+ } catch (IOException e ) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+ try {
+ while ( (profileId = reader.readLine() ) != null ) {
+ // TODO check if the profile ID exists
+ profileIDs.add( profileId );
+ }
+ reader.close();
+ } catch (IOException e) {
+ throw e;
+ }
+
+ return profileIDs;
+ }
+
+ private void writeAssignments( String aEntityId, HashSet aProfileIDs ) throws SPIException {
+ PrintWriter writer;
+ HashSet profileIDs;
+ String profileId;
+ Iterator it;
+ StringBuffer fileName;
+
+
+ try {
+ fileName = new StringBuffer( aEntityId.replace(' ', '+') );
+ fileName.append(DEFAULT_EXTENSION);
+ writer = new PrintWriter( new FileWriter( new File( mFile, fileName.toString() )));
+ it = aProfileIDs.iterator();
+ while ( it.hasNext() ) {
+ writer.println( (String)it.next() );
+ }
+ writer.close();
+ } catch ( MalformedURLException e ) {
+ throw new IllegalWriteException(
+ IllegalWriteException.FILE_WRITE_KEY, e);
+ } catch (IOException e) {
+ throw new IllegalWriteException(
+ IllegalWriteException.FILE_WRITE_KEY, e);
+ }
+ }
+
+ private Entity getEntity( String aEntityId ) throws SPIException {
+ Entity entity = null;
+
+ entity = mPolicySource.getEntityProvider().getEntity(aEntityId);
+
+ return entity;
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileDomain.java b/src/com/sun/apoc/spi/file/entities/FileDomain.java
new file mode 100644
index 0000000..290d1e7
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileDomain.java
@@ -0,0 +1,190 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+import com.sun.apoc.spi.PolicySource;
+import java.util.Iterator;
+import java.util.Vector;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Host;
+
+
+public class FileDomain extends FileNode implements Domain {
+
+ /**
+ * @param aDisplayName
+ * @param aId
+ * @param aParent
+ * @param aAssignment
+ */
+ public FileDomain(String aDisplayName, String aId, Entity aParent, PolicySource aPolicySource) {
+ super(aDisplayName, aId, aParent, aPolicySource);
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Domain#getHosts()
+ */
+ public Iterator getHosts() throws SPIException {
+ return getLeaves();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Domain#getSubDomains()
+ */
+ public Iterator getSubDomains() throws SPIException {
+ return getNodes();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#findEntities(java.lang.String, boolean)
+ */
+ public Iterator findEntities(String aFilter, boolean aIsRecursive)
+ throws SPIException
+ {
+ Iterator nodeIt;
+ Iterator leafIt;
+ Vector entities = new Vector();
+
+
+
+ nodeIt = ((Domain)this).findSubDomains(aFilter, aIsRecursive);
+ leafIt = ((Domain)this).findHosts(aFilter, aIsRecursive);
+
+ while (nodeIt.hasNext()) {
+ entities.add(nodeIt.next());
+ }
+ while (leafIt.hasNext()) {
+ entities.add(leafIt.next());
+ }
+
+ return entities.iterator();
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Domain#findSubDomains(java.lang.String, boolean)
+ */
+ public Iterator findSubDomains(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Iterator domainIt;
+ Domain subDomain;
+ Vector foundDomains;
+ Vector domains;
+ Iterator it;
+ String domainId = getIdFromFilter(aFilter);
+ boolean filterIds = domainId.length() != 0 ;
+
+ foundDomains = new Vector();
+ domains = getDomains(this,aIsRecursive);
+ domainIt = domains.iterator();
+ while (domainIt.hasNext()) {
+ Domain domain = (Domain)domainIt.next();
+ if (!filterIds || domain.getId().indexOf(domainId) != -1) {
+ foundDomains.add(domain);
+ }
+ }
+ return foundDomains.iterator();
+ }
+
+ private Vector getDomains(Domain aDomain, boolean aIsRecursive)
+ throws SPIException {
+ Vector domains;
+ Iterator domainsIt;
+
+ domains = new Vector();
+ domainsIt = aDomain.getSubDomains();
+ while (domainsIt.hasNext()) {
+ Domain domain = (Domain)domainsIt.next();
+ domains.add(domain);
+ if (aIsRecursive) {
+ domains.addAll(getDomains(domain, aIsRecursive));
+ }
+ }
+
+ return domains;
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Domain#findHosts(java.lang.String, boolean)
+ */
+ public Iterator findHosts(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Iterator hostIt;
+ Domain subDomain;
+ Vector foundHosts;
+ String hostId;
+ Iterator it;
+
+ foundHosts = new Vector();
+ hostId = getIdFromFilter(aFilter);
+
+ hostIt = findInLeafs( hostId, this);
+ if ( hostIt.hasNext() || !aIsRecursive ) {
+ return hostIt;
+ } else {
+ it = getSubDomains();
+ while ( it.hasNext() ) {
+ subDomain = (Domain)it.next();
+ hostIt = subDomain.findHosts( hostId, aIsRecursive );
+ while (hostIt.hasNext()) {
+ foundHosts.add(hostIt.next());
+ }
+ }
+ }
+
+ return foundHosts.iterator();
+ }
+
+ private Iterator findInLeafs( String aHostId, Domain aDomain ) throws SPIException {
+ Iterator it;
+ Host host;
+ Vector v;
+ boolean filterIds = aHostId.length() != 0 ;
+
+ v = new Vector();
+ it = aDomain.getHosts();
+ while ( it.hasNext() ) {
+ host = (Host)it.next();
+ if (!filterIds || host.getId().indexOf(aHostId) != -1) {
+ v.add(host);
+
+ }
+ }
+ return v.iterator();
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileDomainProvider.java b/src/com/sun/apoc/spi/file/entities/FileDomainProvider.java
new file mode 100644
index 0000000..c28b744
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileDomainProvider.java
@@ -0,0 +1,175 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.DomainTreeProvider;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Node;
+
+public class FileDomainProvider extends FileEntityProvider implements DomainTreeProvider {
+ private static final String DEFAULT_DOMAIN_CONTAINER = "entities.txt";
+
+
+ public FileDomainProvider( PolicySource aPolicySource, String aUrl ) throws SPIException {
+ super( aPolicySource, aUrl, DEFAULT_DOMAIN_CONTAINER );
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.DomainTreeProvider#getRootDomain()
+ */
+ public Domain getRootDomain() throws SPIException {
+ if ( !mDataIsLoaded ) {
+ loadData();
+ }
+ return (Domain) mRootNode ;
+ }
+
+ protected void loadData() throws SPIException {
+ String line;
+ File file;
+
+ if ( mDataIsLoaded ) { return ; }
+
+ try {
+ BufferedReader reader = new BufferedReader( new InputStreamReader( mLocation.openStream()));
+ while ( ( line = reader.readLine() ) != null ) {
+ if ( line.startsWith("h:") ) {
+ // Host
+ createEntities( true, line );
+ } else if ( line.startsWith("d:") ) {
+ // Domain
+ createEntities( false, line );
+ }
+ }
+ reader.close();
+ if ( mRootNode == null ) { //empty file readed
+ // Create an empty root node
+ mRootNode = new FileDomain("", "fakeDomainRoot", null, mPolicySource );
+ }
+ } catch (FileNotFoundException e) {
+ // Shouldn't happend
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ } catch (IOException e) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+
+ mDataIsLoaded = true;
+ }
+
+ private void createEntities(boolean aIsHost, String aLine)
+ throws SPIException {
+ String[] components;
+ FileHost host;
+ FileNode parent;
+ Node node;
+ Iterator it;
+ StringBuffer id;
+ int i;
+
+ if (aLine.indexOf('/') != -1 ) {
+ components = aLine.split("/");
+ /*
+ * Eliminate the possibility of having the Domain root and Organization
+ * root with the sameid
+ */
+ id = new StringBuffer(components[1]).append(FileEntity.DOMAIN_TAG);
+
+ if (mRootNode == null ) {
+ mRootNode = new FileDomain(components[1], id.toString(), null,
+ mPolicySource);
+ } else if (!mRootNode.getId().contentEquals(id)) {
+ // Different root. ignore line
+ return;
+ }
+
+ if ( components.length > 2 ) {
+ parent = (FileNode) mRootNode;
+ for (i = 2; i < components.length - 1; i++) // process nodes
+ {
+ it = ((Node) parent).getChildren();
+ id.append(FileEntity.ENTITY_SEPARATOR);
+ id.append(components[i]);
+ if (!contains(it, id.toString())) {
+ node = new FileDomain( components[i], id.toString(),
+ parent, mPolicySource);
+ parent.addChildNode(node);
+ parent = (FileNode) node;
+ } else {
+ parent = (FileNode) internalGetEntity(id.toString());
+ }
+ }
+
+ id.append(FileEntity.ENTITY_SEPARATOR);
+ id.append(components[i]);
+ if ( aIsHost ) {
+ // leaf -> create host
+ host = new FileHost(components[i],id.toString(), parent,
+ mPolicySource);
+ parent.addChildLeaf( host );
+ } else {
+ node = new FileDomain( components[i], id.toString(), parent,
+ mPolicySource);
+ parent.addChildNode( node );
+ }
+ }
+ }
+ }
+
+ private boolean contains( Iterator it, String aId ) {
+ Entity entity;
+ while ( it.hasNext() ) {
+ entity = (Entity) it.next();
+ if ( entity.getId().equals( aId ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileEntity.java b/src/com/sun/apoc/spi/file/entities/FileEntity.java
new file mode 100644
index 0000000..67ce5d5
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileEntity.java
@@ -0,0 +1,113 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import com.sun.apoc.spi.PolicySource;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale ;
+import java.util.StringTokenizer;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.AbstractEntity;
+import com.sun.apoc.spi.entities.Entity;
+
+public class FileEntity extends AbstractEntity
+{
+ public static final String ENTITY_SEPARATOR = "_";
+ public static final String DOMAIN_TAG = "Dom";
+ public static final String ORGANIZATION_TAG = "Org";
+
+ private Entity mParent;
+ private String mDisplayName ;
+
+ public FileEntity( String aDisplayName, String aId, Entity aParent, PolicySource aPolicySource )
+ {
+ mDisplayName = aDisplayName;
+ mId = aId;
+ mParent = aParent;
+ mPolicySource = aPolicySource;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Entity#getDisplayName()
+ */
+ public String getDisplayName(Locale aLocale)
+ {
+ return mDisplayName;
+ }
+
+ public Iterator getAncestorNames(Locale aLocale) {
+ LinkedList ancestorNames = new LinkedList();
+ StringTokenizer elements = new StringTokenizer(mId, FileEntity.ENTITY_SEPARATOR);
+ if (elements.hasMoreTokens()) {
+ String rootElement = elements.nextToken();
+ if (rootElement.endsWith(FileEntity.ORGANIZATION_TAG)) {
+ int newRootElementLength = rootElement.length() - FileEntity.ORGANIZATION_TAG.length();
+ rootElement = rootElement.substring(0, newRootElementLength);
+ }
+ else if (rootElement.endsWith(FileEntity.DOMAIN_TAG)) {
+ int newRootElementLength = rootElement.length() - FileEntity.DOMAIN_TAG.length();
+ rootElement = rootElement.substring(0, newRootElementLength);
+ }
+ ancestorNames.add(rootElement);
+ }
+ while (elements.hasMoreTokens()) {
+ ancestorNames.add(elements.nextToken());
+ }
+ // the last element is the name of this entity, so it's not part of the ancestors
+ if (ancestorNames.size() > 0) {
+ ancestorNames.removeLast();
+ }
+ return ancestorNames.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Entity#getParent()
+ */
+ public Entity getParent()
+ {
+ return mParent;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Entity#getLayeredProfiles()
+ */
+ public Iterator getLayeredProfiles() throws SPIException
+ {
+ Iterator parents = getAllParents();
+ return getLayeredProfiles(parents, null);
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileEntityProvider.java b/src/com/sun/apoc/spi/file/entities/FileEntityProvider.java
new file mode 100644
index 0000000..07451c6
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileEntityProvider.java
@@ -0,0 +1,178 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.OpenConnectionException;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.EntityTreeProvider;
+import com.sun.apoc.spi.entities.Node;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.environment.InvalidParameterException;
+import com.sun.apoc.spi.environment.MissingParameterException;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+
+abstract public class FileEntityProvider implements EntityTreeProvider {
+ protected PolicySource mPolicySource;
+ protected boolean mDataIsLoaded;
+ protected Node mRootNode;
+ protected URL mLocation;
+
+ public FileEntityProvider( PolicySource aPolicySource, String aUrl, String aContainerFile ) throws SPIException {
+ if ( (aUrl == null) || (aUrl.length() == 0)) {
+ throw new MissingParameterException("domain "+EnvironmentConstants.URL_KEY);
+ }
+ StringBuffer location;
+ location = new StringBuffer(aUrl);
+ if ( location.charAt(location.length() - 1) != '/' ) {
+ location.append('/');
+ }
+ location.append(aContainerFile);
+ try {
+ mLocation = new URL( location.toString() );
+ } catch ( MalformedURLException e ) {
+ throw new InvalidParameterException(
+ "domain "+EnvironmentConstants.URL_KEY,
+ location.toString());
+ }
+ mPolicySource = aPolicySource;
+ mRootNode = null;
+ mDataIsLoaded = false;
+
+ }
+
+ public void open() throws SPIException
+ {
+ File file;
+
+ if ( mLocation.getProtocol().equals(EnvironmentConstants.FILE_URL_PROTOCOL) ) {
+ try {
+ file = new File( new URI( mLocation.toString() ) );
+ if ( !file.exists() ) {
+ throw new IllegalReadException(IllegalReadException.FILE_NAME_READ_KEY, file.getAbsolutePath());
+ }
+ } catch ( URISyntaxException e ){
+ throw new InvalidParameterException(
+ "organization "+EnvironmentConstants.URL_KEY,
+ mLocation.toString());
+ }
+
+ } else {
+ try {
+ mLocation.openStream();
+ } catch (IOException e) {
+ // could not connect to the repository
+ throw new OpenConnectionException(
+ mLocation.toString(), e);
+ }
+ }
+ }
+
+ public void close() throws SPIException
+ {
+ // Nothing to do
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.EntityProvider#getRootEntity()
+ */
+ public Node getRootEntity() throws SPIException {
+ if ( !mDataIsLoaded ) {
+ loadData();
+ mDataIsLoaded = true;
+ }
+ return mRootNode;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.EntityProvider#getEntity(java.lang.String)
+ */
+ public Entity getEntity(String aId) throws SPIException {
+ if ( !mDataIsLoaded ) {
+ loadData();
+ }
+ return internalGetEntity( aId );
+ }
+
+ protected Entity internalGetEntity(String aId) throws SPIException {
+ LinkedList toVisit;
+ Entity entity;
+ Iterator it;
+
+ entity = mRootNode;
+
+ if ( entity.getId().equals( aId ) ) {
+ return entity;
+ } else {
+ toVisit = new LinkedList();
+ addChilds( toVisit, (Node)entity );
+
+ while ( !toVisit.isEmpty() ) {
+ entity = (Entity) toVisit.removeFirst();
+ if ( entity.getId().equals( aId ) ) {
+ return entity;
+ }
+ if ( entity instanceof Node ) {
+ addChilds( toVisit, (Node)entity );
+ }
+ }
+ }
+ // Not found
+ return null;
+ }
+
+ private void addChilds( LinkedList aList, Node aNode ) throws SPIException {
+ Iterator it;
+
+ it = aNode.getChildren();
+ while ( it.hasNext()) {
+ aList.add( (Entity)it.next() );
+ }
+ }
+
+ abstract protected void loadData() throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileHost.java b/src/com/sun/apoc/spi/file/entities/FileHost.java
new file mode 100644
index 0000000..f938c7f
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileHost.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import com.sun.apoc.spi.PolicySource;
+import java.util.Collections;
+import java.util.Iterator;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Host;
+
+public class FileHost extends FileEntity implements Host
+{
+ /**
+ * @param aDisplayName
+ * @param aId
+ * @param aParent
+ * @param aAssignment
+ */
+ public FileHost(String aDisplayName, String aId, Entity aParent, PolicySource aPolicySource )
+ {
+ super(aDisplayName, aId, aParent, aPolicySource);
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Leaf#getMemberships()
+ */
+ public Iterator getMemberships() throws SPIException
+ {
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileNode.java b/src/com/sun/apoc/spi/file/entities/FileNode.java
new file mode 100644
index 0000000..0d1d601
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileNode.java
@@ -0,0 +1,254 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Leaf;
+import com.sun.apoc.spi.entities.Node;
+
+abstract public class FileNode extends FileEntity implements Node
+{
+ Map mLeaves;
+ Map mNodes;
+ Map mRoles;
+
+ /**
+ * @param aDisplayName
+ * @param aId
+ * @param aParent
+ * @param aPolicyManager
+ */
+ public FileNode(String aDisplayName, String aId, Entity aParent, PolicySource aPolicySource)
+ {
+ super(aDisplayName, aId, aParent, aPolicySource);
+ mLeaves = Collections.synchronizedMap( new HashMap() );
+ mNodes = Collections.synchronizedMap( new HashMap() );
+ mRoles = Collections.synchronizedMap( new HashMap() );
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#findEntities(java.lang.String, boolean)
+ */
+ abstract public Iterator findEntities(String aFilter, boolean aIsRecursive)
+ throws SPIException;
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#getRoles()
+ */
+ public Iterator getRoles() throws SPIException
+ {
+ return mRoles.values().iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#hasRoles()
+ */
+ public boolean hasRoles() throws SPIException
+ {
+ return !mRoles.isEmpty();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#getChildren()
+ */
+ public Iterator getChildren() throws SPIException
+ {
+ LinkedList children;
+ Iterator it;
+
+ children = new LinkedList();
+
+ it = mLeaves.values().iterator();
+ while ( it.hasNext() )
+ {
+ children.add( (Entity)it.next());
+ }
+
+ it = mNodes.values().iterator();
+ while ( it.hasNext() )
+ {
+ children.add( (Node)it.next());
+ }
+
+ it = mRoles.values().iterator();
+ while ( it.hasNext() )
+ {
+ children.add( (Entity)it.next() );
+ }
+
+
+ return children.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#hasChildren()
+ */
+ public boolean hasChildren() throws SPIException
+ {
+ return ( hasLeaves() || hasNodes() || hasRoles() );
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#getLeaves()
+ */
+ public Iterator getLeaves() throws SPIException
+ {
+ return mLeaves.values().iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#hasLeaves()
+ */
+ public boolean hasLeaves() throws SPIException
+ {
+ return !mLeaves.isEmpty();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#getNodes()
+ */
+ public Iterator getNodes() throws SPIException
+ {
+ return mNodes.values().iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#hasNodes()
+ */
+ public boolean hasNodes() throws SPIException
+ {
+ return !mNodes.isEmpty();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Node#getEntity(java.lang.String)
+ */
+ public Entity getEntity(String aId) throws SPIException
+ {
+ Entity entity;
+
+ entity = depthSearch(this, aId);
+ return entity;
+ }
+
+ private Entity depthSearch(FileNode aNode, String aId ) {
+ FileNode node;
+ Entity entity;
+ Iterator it;
+
+ entity = null;
+ if ( aNode.getId().equals(aId)) {
+ return aNode;
+ }
+ it = aNode.mLeaves.values().iterator();
+ entity = searchForEntity( it, aId );
+ it = aNode.mNodes.values().iterator();
+ while ((it.hasNext()) && (entity == null)) {
+ node = (FileNode)it.next();
+ entity = depthSearch(node, aId);
+ }
+
+ return entity;
+ }
+
+ protected void addChildNode( Node aNode )
+ {
+ mNodes.put( aNode.getId(), aNode );
+ }
+
+ protected void addChildLeaf( Leaf aLeaf)
+ {
+ mLeaves.put( aLeaf.getId(), aLeaf );
+
+ }
+ private Entity searchForEntity( Iterator aIt, String aId )
+ {
+ Entity entity;
+
+ while (aIt.hasNext())
+ {
+ entity = (Entity) aIt.next();
+ if ( aId.indexOf(entity.getId()) != -1 )
+ {
+ return entity;
+ }
+ }
+
+ return null;
+ }
+
+ protected String getIdFromFilter( String aFilter) {
+ // aFilter:
+ // (givenname="*userid*")
+ // (cn="*userId*")
+ // (sn="*userId*")
+ // *userId*
+ String uid;
+
+ if ( aFilter == null ) {
+ return null;
+ }
+
+ uid = aFilter;
+ if ( aFilter.startsWith("(") && aFilter.endsWith(")")) {
+ // remove ( & )
+ uid = aFilter.substring(1, aFilter.length()-1);
+ String[] tokens = uid.split("=");
+ if ( tokens.length == 2 ) {
+ uid=tokens[tokens.length-1];
+ }
+ }
+
+ if ( uid.startsWith("*") && uid.endsWith("*") && uid.length() > 2) {
+ // remove * at the begining and at the end
+ uid = uid.substring(1,uid.length()-1);
+ }
+
+ if (uid.equals("*")) {
+ uid ="";
+ }
+
+ return uid;
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileOrganization.java b/src/com/sun/apoc/spi/file/entities/FileOrganization.java
new file mode 100644
index 0000000..527b6c0
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileOrganization.java
@@ -0,0 +1,191 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.entities.User;
+
+public class FileOrganization extends FileNode implements Organization {
+
+ /**
+ * @param aDisplayName
+ * @param aId
+ * @param aParent
+ * @param aAssignment
+ */
+ public FileOrganization(String aDisplayName, String aId, Entity aParent, PolicySource aPolicySource) {
+ super(aDisplayName, aId, aParent, aPolicySource);
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Organization#getUsers()
+ */
+ public Iterator getUsers() throws SPIException {
+ return getLeaves();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Organization#getSubOrganizations()
+ */
+ public Iterator getSubOrganizations() throws SPIException {
+ return getNodes();
+ }
+
+ public Iterator findEntities(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Iterator nodeIt;
+ Iterator leafIt;
+ Vector entities = new Vector();
+
+ nodeIt = ((Organization)this).findSubOrganizations(aFilter, aIsRecursive);
+ leafIt = ((Organization)this).findUsers(aFilter, aIsRecursive);
+ while (nodeIt.hasNext()) {
+ entities.add(nodeIt.next());
+ }
+ while (leafIt.hasNext()) {
+ entities.add(leafIt.next());
+ }
+
+ return entities.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Organization#findSubOrganizations(java.lang.String, boolean)
+ */
+ public Iterator findSubOrganizations(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Iterator domainIt;
+ Organization subOrg;
+ Vector foundOrgs;
+ Vector orgs;
+ Iterator it;
+ String orgId = getIdFromFilter(aFilter);
+
+ foundOrgs = new Vector();
+ orgs = getOrganizations(this,aIsRecursive);
+ domainIt = orgs.iterator();
+ while (domainIt.hasNext()) {
+ Organization org = (Organization)domainIt.next();
+ if (org.getId().indexOf(orgId) != -1 || orgId.equals("")) {
+ foundOrgs.add(org);
+ }
+ }
+ return foundOrgs.iterator();
+ }
+
+ private Vector getOrganizations(Organization aOrg, boolean aIsRecursive)
+ throws SPIException {
+ Vector organizations;
+ Iterator orgIt;
+
+ organizations = new Vector();
+ orgIt = aOrg.getSubOrganizations();
+ while (orgIt.hasNext()) {
+ Organization org = (Organization)orgIt.next();
+ organizations.add(org);
+ if (aIsRecursive) {
+ organizations.addAll(getOrganizations(org, aIsRecursive));
+ }
+ }
+
+ return organizations;
+
+ }
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Organization#findUsers(java.lang.String, boolean)
+ */
+ public Iterator findUsers(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ String userId;
+
+ userId = getIdFromFilter(aFilter);
+ if (userId == null ) {
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ return findUsersRecursive(userId, aIsRecursive);
+ }
+
+ private Iterator findUsersRecursive(String aUserId, boolean aIsRecursive)
+ throws SPIException {
+ FileOrganization subOrg;
+ Iterator userIt;
+ Vector foundUsers;
+ Iterator it;
+
+ foundUsers = new Vector();
+ userIt = findInLeafs( aUserId, this);
+ if ( userIt.hasNext() || !aIsRecursive ) {
+ return userIt;
+ } else {
+ it = getSubOrganizations();
+ while ( it.hasNext() ) {
+ subOrg = (FileOrganization)it.next();
+ userIt = subOrg.findUsersRecursive( aUserId, aIsRecursive );
+ while( userIt.hasNext() ) {
+ foundUsers.add(userIt.next());
+ }
+ }
+ }
+
+ return foundUsers.iterator();
+ }
+
+ private Iterator findInLeafs( String aUserId, Organization aOrg ) throws SPIException {
+ Iterator it;
+ User user;
+ Vector v;
+
+ v = new Vector();
+ it = aOrg.getUsers();
+ while ( it.hasNext() ) {
+ user = (User)it.next();
+ if ( user.getId().indexOf(aUserId) != -1 || aUserId.equals("") ) {
+ v.add(user);
+ }
+ }
+ return v.iterator();
+ }
+
+
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileOrganizationProvider.java b/src/com/sun/apoc/spi/file/entities/FileOrganizationProvider.java
new file mode 100644
index 0000000..f946a34
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileOrganizationProvider.java
@@ -0,0 +1,193 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Node;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.entities.OrganizationTreeProvider;
+
+public class FileOrganizationProvider extends FileEntityProvider implements
+OrganizationTreeProvider
+{
+ private static final String DEFAULT_ORG_CONTAINER = "entities.txt";
+
+ public FileOrganizationProvider( PolicySource aPolicySource, String aUrl ) throws SPIException
+ {
+ super(aPolicySource,aUrl, DEFAULT_ORG_CONTAINER);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.sun.apoc.spi.entities.OrganizationTreeProvider#getRootOrganization()
+ */
+ public Organization getRootOrganization() throws SPIException
+ {
+ if (!mDataIsLoaded) {
+ loadData();
+ }
+ return (Organization) mRootNode;
+ }
+
+ protected void loadData() throws SPIException
+ {
+ String line;
+ File file;
+
+ if (mRootNode != null)
+ {
+ return;
+ }
+
+ try
+ {
+ BufferedReader reader = new BufferedReader( new InputStreamReader( mLocation.openStream()));
+ while ((line = reader.readLine()) != null)
+ {
+ if (( line.startsWith("u:")) && !line.endsWith("/") ) {
+ // User
+ createEntities(true, line);
+ } else if ( line.startsWith("o:") ) {
+ createEntities(false, line);
+ }
+ }
+ reader.close();
+ if ( mRootNode == null ) { //empty file readed
+ // Create an empty root node
+ mRootNode = new FileOrganization("", "fakeOrgRoot", null, mPolicySource );
+ }
+ }
+ catch (FileNotFoundException e)
+ {
+ // Shouldn't happend. the existence of the file is checked in the
+ // open method
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+
+ mDataIsLoaded = true;
+ }
+
+ private void createEntities(boolean aIsUser, String aLine) throws SPIException
+ {
+ String[] components;
+ FileUser user;
+ FileNode parent;
+ Node node;
+ Iterator it;
+ StringBuffer id;
+ int i;
+
+ if (aLine.indexOf('/') != -1 ) {
+ components = aLine.split("/");
+ /*
+ * Eliminate the possibility of having the Domain root and Organization
+ * root with the same Id
+ */
+ id = new StringBuffer(components[1]).append(FileEntity.ORGANIZATION_TAG);
+
+ if (mRootNode == null) {
+ mRootNode = new FileOrganization(components[1], id.toString(),
+ null, mPolicySource);
+ } else if (!mRootNode.getId().contentEquals(id)) {
+ // Differnet root. ignore line
+ return;
+ }
+
+ if ( components.length > 2 ) {
+ parent = (FileNode) mRootNode;
+ for (i = 2; i < components.length - 1; i++) // process nodes
+ {
+ it = ((Node) parent).getChildren();
+ id.append(FileEntity.ENTITY_SEPARATOR);
+ id.append(components[i]);
+ if (!contains(it, id.toString()))
+ {
+ node = new FileOrganization(components[i], id.toString(), parent,
+ mPolicySource);
+ parent.addChildNode(node);
+ parent = (FileNode) node;
+ }
+ else
+ {
+ parent = (FileNode) internalGetEntity(id.toString());
+ }
+ }
+ id.append(FileEntity.ENTITY_SEPARATOR);
+ id.append(components[i]);
+ if ( aIsUser ) {
+ // leaf -> create user
+ user = new FileUser(components[i], id.toString(), parent, mPolicySource);
+ parent.addChildLeaf(user);
+ } else {
+ node = new FileOrganization( components[i], id.toString(), parent, mPolicySource);
+ parent.addChildNode( node );
+ }
+ }
+ }
+ }
+
+ private boolean contains(Iterator it, String aId)
+ {
+ Entity entity;
+ while (it.hasNext())
+ {
+ entity = (Entity) it.next();
+ if (entity.getId().equals(aId))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/entities/FileUser.java b/src/com/sun/apoc/spi/file/entities/FileUser.java
new file mode 100644
index 0000000..eab4b3b
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/entities/FileUser.java
@@ -0,0 +1,85 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.entities;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.User;
+import com.sun.apoc.spi.profiles.Profile;
+
+public class FileUser extends FileEntity implements User
+{
+
+ /**
+ * @param aDisplayName
+ * @param aId
+ * @param aParent
+ * @param aAssignment
+ */
+ public FileUser(String aDisplayName, String aId, Entity aParent, PolicySource aPolicySource )
+ {
+ super(aDisplayName, aId, aParent, aPolicySource);
+ }
+
+ public String getUserId()
+ {
+ return getDisplayName(null);
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.entities.Leaf#getMemberships()
+ */
+ public Iterator getMemberships() throws SPIException
+ {
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ /**
+ * no virtual user profile for a file user,
+ * return null
+ *
+ * @return null
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getUserProfile() throws SPIException {
+ return null;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/file/environment/FileConfigurationProvider.java b/src/com/sun/apoc/spi/file/environment/FileConfigurationProvider.java
new file mode 100644
index 0000000..57f09cb
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/environment/FileConfigurationProvider.java
@@ -0,0 +1,108 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.file.environment;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.environment.ConfigurationProvider;
+import com.sun.apoc.spi.environment.RemoteEnvironmentException;
+
+public class FileConfigurationProvider implements ConfigurationProvider {
+
+ protected String[] mFileURLs;
+
+ /**
+ * Constructor
+ *
+ * @param urls urls of the files to get
+ * the configuration data from
+ */
+ public FileConfigurationProvider(String[] urls) {
+ mFileURLs = urls;
+ }
+
+ /**
+ * Loads the configuration data from the different files
+ * and put them all in the same Hashtable returned
+ *
+ * @return the Hashtable containing all the parameters
+ * read from the different files
+ * @throws SPIException if error occurs
+ * @see com.sun.apoc.spi.environment.ConfigurationProvider#loadData()
+ */
+ public Hashtable loadData() throws SPIException {
+ Hashtable data = new Hashtable();
+ if (mFileURLs != null) {
+ for (int i=0; i<mFileURLs.length; i++) {
+ data.putAll(loadFileData(mFileURLs[i]));
+ }
+ }
+ return data;
+ }
+
+ /**
+ * Loads the configuration data from the specified file
+ * and return a Hashtable containing them
+ *
+ * @param fileURL url of the file to get the data from
+ * @return the Hashtable containing the parameters
+ * read in the file
+ * @throws SPIException if error occurs
+ */
+ private Hashtable loadFileData(String fileURL) throws SPIException {
+ Properties propertyList = new Properties();
+ try {
+ URL url = new URL(fileURL);
+ InputStream input = url.openStream();
+ propertyList.load(input);
+ input.close();
+ } catch (MalformedURLException mue) {
+ throw new RemoteEnvironmentException(
+ RemoteEnvironmentException.FILE_CONF_KEY,
+ new Object[]{fileURL}, mue);
+ } catch (IOException ioe) {
+ throw new RemoteEnvironmentException(
+ RemoteEnvironmentException.FILE_CONF_KEY,
+ new Object[]{fileURL}, ioe);
+ }
+ return propertyList;
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/profiles/FileProfile.java b/src/com/sun/apoc/spi/file/profiles/FileProfile.java
new file mode 100644
index 0000000..a91cd0c
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/profiles/FileProfile.java
@@ -0,0 +1,644 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.profiles;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Properties;
+import java.util.zip.ZipException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.IllegalWriteException;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.policies.PolicyInfo;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.InvalidPriorityException;
+import com.sun.apoc.spi.profiles.InvalidProfileException;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+import com.sun.apoc.spi.profiles.ProfileStreamException;
+import com.sun.apoc.spi.profiles.ProfileZipException;
+import com.sun.apoc.spi.profiles.ZipProfileReadWrite;
+
+
+public class FileProfile implements Profile {
+ // field variables
+ private ProfileRepository mRepository;
+ private Applicability mApplicability;
+ private final int BUFSIZE = 2028;
+ private PolicySource mPolicySource;
+ private String mDisplayName;
+ private Map mPolicyCache;
+ private URL mProfileURL;
+ private String mComment;
+ private String mAuthor;
+ private int mPriority;
+ private String mId;
+ private long mLastModified;
+
+ public static Profile loadProfile( String aId, ProfileRepository aRepository,
+ PolicySource aPolicySource ) throws SPIException {
+ Applicability applicability = null;
+ BufferedReader metaDataStream;
+ String displayName = null;
+ String author = "";
+ String comment = "";
+ Hashtable metaData;
+ int priority = 0;
+ Profile profile;
+ URL profileURL;
+
+ profile = null;
+ profileURL = null;
+
+ profileURL = getProfileURL( aId, aRepository );
+ /*
+ metaData = getMetaData( profileURL );
+ if ( metaData.containsKey( DISPLAYNAME ) ) {
+ displayName = (String) metaData.get( DISPLAYNAME );
+ }
+
+ if ( metaData.containsKey( COMMENT ) ) {
+ comment = (String) metaData.get( COMMENT );
+ }
+
+ if ( metaData.containsKey( APPLICABILITY ) ) {
+ String applicabilityStr = (String) metaData.get( APPLICABILITY );
+ applicability = Applicability.getApplicability( applicabilityStr );
+ }
+ if ( metaData.containsKey( PRIORITY ) ) {
+ String priorityStr = (String) metaData.get( PRIORITY );
+ priority = new Integer( priorityStr ).intValue();
+ }
+
+ if ( metaData.containsKey( AUTHOR ) ) {
+ author = (String)metaData.get( AUTHOR );
+ }
+ */
+ profile = new FileProfile( aId, aRepository, displayName, comment, applicability, priority,
+ profileURL, aPolicySource, author, true );
+
+ return profile;
+ }
+
+ public static Profile createNewProfile( ProfileRepository aRepository,
+ String aDisplayName, Applicability aApplicability, int aPriority,
+ PolicySource aPolicySource ) throws SPIException {
+ ZipOutputStream out;
+ URL profileURL;
+ String author;
+ ZipEntry entry;
+ StringBuffer id;
+ Profile profile = null;
+
+ if ( aRepository.isReadOnly() ) {
+ throw new IllegalWriteException();
+ }
+
+ Random randomizer = new Random();
+ id = new StringBuffer( aRepository.getId() ).append("-");
+ id.append( Integer.toString( Math.abs( randomizer.nextInt() ) ) );
+
+ profileURL = getProfileURL( id.toString(), aRepository );
+
+ author = "";
+ if ( aPolicySource.getEnvironment().containsKey( EnvironmentConstants.USER_KEY ) ) {
+ author = (String) aPolicySource.getEnvironment().get( EnvironmentConstants.USER_KEY );
+ }
+ // create the profile
+ profile = new FileProfile(id.toString(), aRepository, aDisplayName, "", aApplicability,
+ aPriority, profileURL, aPolicySource, author, false );
+
+ ((FileProfile)profile).writeProfile();
+
+ return profile;
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#setPriority(int)
+ */
+ public void setPriority(int aPriority) throws SPIException {
+ if (((FileProfileRepository)mRepository).priorityExists( aPriority ) ) {
+ throw new InvalidPriorityException(
+ InvalidPriorityException.USED_PRIORITY_KEY, aPriority);
+ }
+
+ mPriority = aPriority;
+ writeProfile();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#setDisplayName(java.lang.String)
+ */
+ public void setDisplayName(String aDisplayName) throws SPIException {
+ if (aDisplayName == null) {
+ throw new IllegalArgumentException();
+ }
+ if ( mRepository.isReadOnly() ) {
+ throw new IllegalWriteException();
+ }
+ mDisplayName = aDisplayName;
+ writeProfile();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#storePolicy(com.sun.apoc.spi.policies.Policy)
+ */
+ public void storePolicy(Policy aPolicy) throws SPIException {
+ if (aPolicy == null) {
+ throw new IllegalArgumentException();
+ }
+ if ( mRepository.isReadOnly() ) {
+ throw new IllegalWriteException();
+ }
+
+ String id = aPolicy.getId();
+
+ if ( mPolicyCache.containsKey( id ) ) {
+ mPolicyCache.remove( id );
+ }
+
+ if ( aPolicy.getData() != null) {
+ Policy policy = aPolicy;
+ if ( aPolicy.getProfileId() == null ) {
+ /* #6283807# policies created with no profileId should get one when
+ * they are stored
+ */
+ policy = new Policy(aPolicy.getId(), this.getId(), aPolicy.getData(), aPolicy.getLastModified());
+ }
+ mPolicyCache.put( id , policy );
+ }
+ writeProfile();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#destroyPolicy(com.sun.apoc.spi.policies.Policy)
+ */
+ public void destroyPolicy(Policy aPolicy) throws SPIException {
+ if ( mRepository.isReadOnly() ) {
+ throw new IllegalWriteException();
+ }
+
+ String id = aPolicy.getId();
+
+ if (mPolicyCache.containsKey( id )) {
+ mPolicyCache.remove( id );
+ }
+
+ writeProfile();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#hasPolicies()
+ */
+ public boolean hasPolicies() throws SPIException {
+ return ( mPolicyCache.size() != 0 );
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getPolicies()
+ */
+ public Iterator getPolicies() throws SPIException {
+ return mPolicyCache.values().iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getPolicies(java.util.ArrayList)
+ */
+ public Iterator getPolicies(ArrayList aPolicyIdList) throws SPIException {
+ LinkedList policyList = new LinkedList();
+ Iterator it = aPolicyIdList.iterator();
+ String policyId;
+
+ while ( it.hasNext() ) {
+ policyId = (String) it.next();
+ if ( mPolicyCache.containsKey( policyId ) ) {
+ policyList.add( mPolicyCache.get( policyId ));
+ }
+ }
+
+ return policyList.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getPolicy(java.lang.String)
+ */
+ public Policy getPolicy(String aId) throws SPIException {
+ if (aId == null) {
+ throw new IllegalArgumentException();
+ }
+ Policy policy = null;
+
+ if ( mPolicyCache.containsKey( aId )) {
+ policy = (Policy)mPolicyCache.get( aId);
+ }
+
+ return policy;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#hasAssignedEntities()
+ */
+ public boolean hasAssignedEntities() throws SPIException {
+ return mPolicySource.getAssignmentProvider().getAssignedEntities( this ).hasNext();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getAssignedEntities()
+ */
+ public Iterator getAssignedEntities() throws SPIException {
+ return mPolicySource.getAssignmentProvider().getAssignedEntities( this );
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#setApplicability(com.sun.apoc.spi.profiles.Applicability)
+ */
+ public void setApplicability(Applicability aApplicability)
+ throws SPIException {
+ if (aApplicability == null) {
+ throw new IllegalArgumentException();
+ }
+ if ( mRepository.isReadOnly() ) {
+ throw new IllegalWriteException();
+ }
+
+ mApplicability = aApplicability;
+
+ writeProfile();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#setComment(java.lang.String)
+ */
+ public void setComment(String aComment) throws SPIException {
+ if (aComment == null) {
+ throw new IllegalArgumentException();
+ }
+ if ( mRepository.isReadOnly() ) {
+ throw new IllegalWriteException();
+ }
+
+ mComment = aComment;
+ writeProfile();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getAuthor()
+ */
+ public String getAuthor() throws SPIException {
+ if (mAuthor == null) {
+ return new String("");
+ }
+ return mAuthor;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object aProfile) {
+ Profile profile;
+
+ profile = (Profile)aProfile;
+ return mId.equals( profile.getId() );
+ }
+
+ private FileProfile( String aId, ProfileRepository aRepository, String aDisplayName,
+ String aComment, Applicability aApplicability, int aPriority, URL aProfileURL,
+ PolicySource aPolicySource, String author, boolean aStored ) throws SPIException {
+ mApplicability = aApplicability;
+ mDisplayName = aDisplayName;
+ mRepository = aRepository;
+ mProfileURL = aProfileURL;
+ mPolicySource = aPolicySource;
+ mPriority = aPriority;
+ mComment = aComment;
+ mAuthor = author;
+ mId = aId;
+
+ mPolicyCache = (Map)Collections.synchronizedMap( new HashMap() );
+
+ if ( aStored ) {
+ readPolicy(); // sets the lastModified from the zip entries
+ } else {
+ mLastModified = System.currentTimeMillis();
+ }
+ }
+
+ private void readPolicy() throws SPIException {
+ ZipInputStream input = null;
+ try {
+ input = new ZipInputStream(mProfileURL.openStream());
+ // first try to read the meta configuration data
+ Properties metaData = ZipProfileReadWrite.readMetaData(input);
+ Iterator it = null;
+ if (metaData != null) {
+ // then try to load the policy data
+ it = ZipProfileReadWrite.readPolicies(input);
+ } else {
+ // if meta data entry does not exist, we assume the old
+ // profile/policy format
+ it = ZipProfileReadWrite.readOldPoliciesFormat(input);
+ // if 'it' contains no data that means it is either an old
+ // format source but with no policies in it or that the source
+ // doesn't have the required format (new or old)
+ // in both cases, raise an exception.
+ if (!it.hasNext()) {
+ input.close();
+ throw new ProfileStreamException(ProfileStreamException.EMPTY_STREAM_KEY);
+ }
+ }
+ input.close();
+
+ // store the policies
+ Policy policy;
+ mLastModified = 0L;
+ while(it.hasNext()) {
+ policy = (Policy)it.next();
+ mPolicyCache.put( policy.getId(), new Policy( policy.getId(), mId, policy.getData(), policy.getLastModified()) );
+ // Although the last modified should be defined in setMetaData
+ // it is possible that some profiles exists without the
+ // lastModified tag in the metadata - SunITOps pre FCS APOC 2.0
+ // deployments - The following if calcualtes the lastModified
+ // bit
+ if ( mLastModified < policy.getLastModified() ) {
+ mLastModified = policy.getLastModified();
+ }
+ }
+
+ // update the meta data
+ setMetaData(metaData);
+ } catch (ZipException ze) {
+ try {
+ input.close();
+ } catch (Exception ignored) {}
+ throw new ProfileZipException(ze);
+
+ } catch (IOException ioe) {
+ try {
+ input.close();
+ } catch (Exception ignored) {}
+ throw new ProfileStreamException(
+ ProfileStreamException.ERROR_STREAM_KEY, ioe);
+ }
+ }
+
+
+ private void writeProfile() throws SPIException {
+ FileOutputStream destFile = null;
+
+ if ( mRepository.isReadOnly() ) {
+ throw new IllegalWriteException();
+ }
+ try {
+ // create the profile repository
+ ((FileProfileRepository)mRepository).createStorage();
+ destFile = new FileOutputStream( mProfileURL.getPath() );
+ } catch (FileNotFoundException e) {
+ throw new IllegalWriteException(
+ IllegalWriteException.FILE_WRITE_KEY, e);
+ }
+
+ // Write data to the file
+ ZipOutputStream output = new ZipOutputStream(destFile);
+ try {
+ mLastModified = System.currentTimeMillis();
+ ZipProfileReadWrite.writeMetaData(this, output);
+ ZipProfileReadWrite.writePolicies(this, output);
+ output.close();
+ destFile.close();
+ } catch (ZipException ze) {
+ try {
+ output.close();
+ destFile.close();
+ } catch (Exception ignored) {}
+ throw new ProfileZipException(ze);
+
+ } catch (IOException ioe) {
+ try {
+ output.close();
+ destFile.close();
+ } catch (Exception ignored) {}
+ throw new ProfileStreamException(
+ ProfileStreamException.ERROR_STREAM_KEY, ioe);
+ }
+ }
+
+ private void setMetaData(Properties aMetaData ) {
+ if ( aMetaData != null ) {
+ if ( aMetaData.containsKey( ZipProfileReadWrite.DISPLAY_NAME ) ) {
+ mDisplayName = (String) aMetaData.get( ZipProfileReadWrite.DISPLAY_NAME );
+ }
+
+ if ( aMetaData.containsKey( ZipProfileReadWrite.COMMENT ) ) {
+ mComment = (String) aMetaData.get( ZipProfileReadWrite.COMMENT );
+ }
+
+ if ( aMetaData.containsKey( ZipProfileReadWrite.APPLICABILITY ) ) {
+ String applicabilityStr = (String) aMetaData.get( ZipProfileReadWrite.APPLICABILITY );
+ mApplicability = Applicability.getApplicability( applicabilityStr );
+ }
+ if ( aMetaData.containsKey( ZipProfileReadWrite.PRIORITY ) ) {
+ String priorityStr = (String) aMetaData.get( ZipProfileReadWrite.PRIORITY );
+ mPriority = new Integer( priorityStr ).intValue();
+ }
+
+ if ( aMetaData.containsKey( ZipProfileReadWrite.AUTHOR ) ) {
+ mAuthor = (String)aMetaData.get( ZipProfileReadWrite.AUTHOR );
+ }
+ if ( aMetaData.containsKey( ZipProfileReadWrite.LAST_MODIFIED )) {
+ mLastModified = Long.parseLong((String)aMetaData.get( ZipProfileReadWrite.LAST_MODIFIED ));
+ }
+ }
+ }
+
+ protected static URL getProfileURL( String aId, ProfileRepository aRepository )
+ throws SPIException {
+ StringBuffer profileURL;
+ String idSplit[];
+ String repId;
+
+ if ( aId.indexOf('-') == -1 ) {
+ throw new InvalidProfileException(
+ InvalidProfileException.ID_PROFILE_KEY,
+ aId);
+ }
+ profileURL = new StringBuffer( ((FileProfileRepository)aRepository).getLocation() );
+ repId = aRepository.getId();
+ // remove the profile ID from the aID
+ idSplit = aId.split("\\Q" + repId + "-\\E");
+ profileURL.append( idSplit[1] );
+ profileURL.append( ".zip" );
+
+ URL url = null;
+ try {
+ url = new URL( profileURL.toString() );
+ } catch (MalformedURLException mue) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, mue);
+ }
+ return url;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getId()
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getDisplayName()
+ */
+ public String getDisplayName() {
+ if (mDisplayName == null) {
+ return new String("");
+ }
+ return mDisplayName;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getPriority()
+ */
+ public int getPriority() {
+ return mPriority;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getLastModified()
+ */
+ public long getLastModified() throws SPIException {
+ return mLastModified;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getApplicability()
+ */
+ public Applicability getApplicability() {
+ return mApplicability;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getComment()
+ */
+ public String getComment() throws SPIException {
+ if (mComment == null) {
+ return new String("");
+ }
+ return mComment;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getProfileRepository()
+ */
+ public ProfileRepository getProfileRepository() {
+ return mRepository;
+ }
+
+ static protected String createId( String aId, String aRepId ) {
+ StringBuffer id;
+
+ id = new StringBuffer( aRepId );
+ id.append( "-");
+ id.append( aId);
+
+ return id.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getPolicies(java.util.Iterator)
+ */
+ public Iterator getPolicies(Iterator aPolicyIdList) throws SPIException {
+ if (aPolicyIdList == null) {
+ throw new IllegalArgumentException();
+ }
+ List policies;
+ String id;
+
+ policies = new LinkedList();
+ while ( aPolicyIdList.hasNext() ) {
+ id = (String)aPolicyIdList.next();
+ if ( mPolicyCache.containsKey( id ) ) {
+ policies.add( mPolicyCache.get( id ) );
+ }
+ }
+ return policies.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.Profile#getPolicyInfos(java.util.Iterator)
+ */
+ public Iterator getPolicyInfos(Iterator aPolicyIdList) throws SPIException {
+ if (aPolicyIdList == null) {
+ throw new IllegalArgumentException();
+ }
+ PolicyInfo policyInfo;
+ List policiesInfo;
+ Policy policy;
+ String id;
+
+ policiesInfo = new LinkedList();
+ while ( aPolicyIdList.hasNext() ) {
+ id = (String)aPolicyIdList.next();
+ if ( mPolicyCache.containsKey( id ) ) {
+ policy = (Policy)mPolicyCache.get( id );
+ policyInfo = new PolicyInfo(id, mId, policy.getLastModified() );
+ policiesInfo.add( policyInfo);
+ }
+ }
+
+ return policiesInfo.iterator();
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/profiles/FileProfileComparator.java b/src/com/sun/apoc/spi/file/profiles/FileProfileComparator.java
new file mode 100644
index 0000000..4b84553
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/profiles/FileProfileComparator.java
@@ -0,0 +1,86 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.profiles;
+
+import java.util.Comparator;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.profiles.Profile;
+
+/**
+ * Compares two FileProfiles according to their priority
+ *
+ */
+public class FileProfileComparator implements Comparator {
+
+ public int compare(Object aProfile1, Object aProfile2) {
+ int profDepth1;
+ int profDepth2;
+ Profile profile1 = (Profile)aProfile1;
+ Profile profile2 = (Profile)aProfile2;
+
+ if (profile1 == null) { return profile2 == null ? 0 : -1 ; }
+ if (profile2 == null) { return 1 ; }
+
+ profDepth1 = getProfileDepth(profile1);
+ profDepth2 = getProfileDepth(profile2);
+ if (profDepth1 != profDepth2 ) {
+ return profDepth1 - profDepth2;
+ }
+
+ if (profile1.getPriority() != profile2.getPriority()) {
+ return profile1.getPriority() - profile2.getPriority() ;
+ }
+ return profile1.getId().compareTo(profile2.getId());
+ }
+
+ private int getProfileDepth(Profile aProfile) {
+ int depth = 0;
+ try {
+ Entity entity = aProfile.getProfileRepository().getEntity();
+
+ while (entity != null ) {
+ depth++;
+ entity = entity.getParent();
+ }
+ } catch (SPIException e) {
+ // should not happend
+ }
+ return depth;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/file/profiles/FileProfileProvider.java b/src/com/sun/apoc/spi/file/profiles/FileProfileProvider.java
new file mode 100644
index 0000000..3770b48
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/profiles/FileProfileProvider.java
@@ -0,0 +1,343 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.profiles;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.OpenConnectionException;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Node;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.environment.InvalidParameterException;
+import com.sun.apoc.spi.environment.MissingParameterException;
+import com.sun.apoc.spi.file.entities.FileEntity;
+import com.sun.apoc.spi.ldap.entities.LdapEntity;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileComparatorProvider;
+import com.sun.apoc.spi.profiles.ProfileProvider;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+
+public class FileProfileProvider implements ProfileProvider, ProfileComparatorProvider
+{
+ private static final String DEFAULT_REP_CONTAINER = "profiles";
+ private PolicySource mPolicySource;
+ private boolean mRemoteRepository;
+ private URL mLocation;
+
+ public FileProfileProvider(PolicySource aPolicySource, String aUrl) throws SPIException
+ {
+ if ( (aUrl == null) || (aUrl.length() == 0)) {
+ throw new MissingParameterException("domain "+EnvironmentConstants.URL_KEY);
+ }
+ StringBuffer location;
+ location = new StringBuffer(aUrl);
+ if ( location.charAt(location.length() - 1) != '/' ) {
+ location.append('/');
+ }
+ if(!(location.toString().endsWith(DEFAULT_REP_CONTAINER + "/"))) {
+ location.append(DEFAULT_REP_CONTAINER).append('/');
+ }
+
+ try {
+ mLocation = new URL( location.toString() );
+ } catch ( MalformedURLException e ) {
+ throw new InvalidParameterException(
+ "domain "+EnvironmentConstants.URL_KEY,
+ location.toString());
+ }
+ mPolicySource = aPolicySource;
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.sun.apoc.spi.profiles.ProfileProvider#getDefaultProfileRepository()
+ */
+ public ProfileRepository getDefaultProfileRepository() throws SPIException
+ {
+ return getProfileRepository(FileProfileRepository.DEFAULT_ID);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.sun.apoc.spi.profiles.ProfileProvider#getProfileRepository(java.lang.String)
+ */
+ public ProfileRepository getProfileRepository(String aId) throws SPIException
+ {
+ ProfileRepository repository = null;
+ StringBuffer path;
+ URL profRepositoryURL;
+
+ try {
+ path = new StringBuffer( FileProfileRepository.PREFIX );
+ path.append( aId.replace(' ', '+') );
+ path.append( "/" );
+
+ profRepositoryURL = new URL(mLocation, path.toString() );
+ } catch ( MalformedURLException e ) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+
+ repository = new FileProfileRepository(mPolicySource, aId, profRepositoryURL );
+
+ return repository;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.sun.apoc.spi.profiles.ProfileProvider#getProfile(java.lang.String)
+ */
+ public Profile getProfile(String aId) throws SPIException
+ {
+ // The Repository id in with a profile is stored is part of the profile
+ // id.
+ Profile profile = null;
+ String[] ids;
+ ids = aId.split("-");
+
+ ProfileRepository repository = getProfileRepository(ids[0]);
+ profile = repository.getProfile(aId);
+
+ return profile;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.sun.apoc.spi.profiles.ProfileProvider#open()
+ */
+ public void open() throws SPIException
+ {
+ File file;
+ // checks if the repository exists
+ if ( mLocation.getProtocol().equals(EnvironmentConstants.FILE_URL_PROTOCOL) ) {
+ mRemoteRepository = false;
+ try {
+ file = new File( new URI(mLocation.toString()));
+ if ( !file.exists() ) {
+ throw new IllegalReadException(IllegalReadException.FILE_NAME_READ_KEY, file.getAbsolutePath());
+ } else if ( !file.isDirectory() ) {
+ throw new InvalidParameterException(
+ "profile "+EnvironmentConstants.URL_KEY,
+ mLocation.toString());
+ }
+ } catch ( URISyntaxException e ) {
+ // Should not happend
+ throw new InvalidParameterException(
+ "profile "+EnvironmentConstants.URL_KEY,
+ mLocation.toString());
+ }
+ } else {
+ mRemoteRepository = true;
+ try {
+ mLocation.openStream();
+ } catch (IOException e) {
+ // could not connect to the repository
+ throw new OpenConnectionException(
+ mLocation.toString(), e);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.sun.apoc.spi.profiles.ProfileProvider#close()
+ */
+ public void close() throws SPIException
+ {
+ // Nothing to do
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileProvider#getAllProfiles()
+ */
+ public Iterator getAllProfiles() throws SPIException {
+ ProfileRepository repository;
+ Iterator profFromRep;
+ List profiles;
+ String id;
+ File file;
+
+ if ( mRemoteRepository ) {
+ // Operation not allowed in a remote repository
+ throw new UnsupportedOperationException();
+ }
+
+ profiles = new LinkedList();
+ try {
+ File profileReps[];
+ file = new File( new URI(mLocation.toString()));
+ profileReps = file.listFiles();
+ // Get profiles from each profile repository
+ for ( int i = 0; i < profileReps.length; i++ ) {
+ if ( profileReps[i].isDirectory() ) {
+ id = getRepIdFromFile( profileReps[i] );
+ if ( id != null ) {
+ repository = getProfileRepository( id );
+ profFromRep = repository.getProfiles(Applicability.getApplicability(mPolicySource.getName()));
+ addProfiles( profiles, profFromRep );
+ }
+ }
+ }
+ } catch ( URISyntaxException e ) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+
+ return profiles.iterator();
+ }
+
+ public Iterator getAllProfiles(Entity startingEntity) throws SPIException {
+ ProfileRepository repository;
+ Iterator profFromRep;
+ List profiles = new LinkedList();;
+ String id;
+ File file;
+
+ if ( mRemoteRepository ) {
+ // Operation not allowed in a remote repository
+ throw new UnsupportedOperationException();
+ }
+
+ if ( (startingEntity instanceof LdapEntity)
+ && ((startingEntity.equals(mPolicySource.getRoot())))) {
+ addProfiles(profiles,
+ startingEntity.getProfileRepository().getProfiles(Applicability.getApplicability(mPolicySource.getName())));
+ Iterator iterEntities = ((Node)startingEntity).getChildren();
+ while (iterEntities.hasNext()) {
+ Entity entity = (Entity)iterEntities.next();
+ profiles.addAll(getAllProfilesInSubEntity(entity));
+ }
+ }
+ else {
+ profiles = getAllProfilesInSubEntity(startingEntity);
+ }
+ return profiles.iterator();
+ }
+
+ private List getAllProfilesInSubEntity (Entity entity) throws SPIException {
+ List profiles = new LinkedList();
+ ProfileRepository repository;
+ Iterator profFromRep;
+ String id;
+ try {
+ File profileReps[];
+ File file = new File( new URI(mLocation.toString()));
+ profileReps = file.listFiles();
+ // Get profiles from each profile repository
+ for ( int i = 0; i < profileReps.length; i++ ) {
+ if ( profileReps[i].isDirectory() ) {
+ id = getRepIdFromFile( profileReps[i] );
+ if (( id != null ) && (isRepIdInSubEntity(id, entity))) {
+ repository = getProfileRepository( id );
+ profFromRep = repository.getProfiles(Applicability.getApplicability(mPolicySource.getName()));
+ addProfiles( profiles, profFromRep );
+ }
+ }
+ }
+ } catch ( URISyntaxException e ) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+ return profiles;
+ }
+
+ public Comparator getProfileComparator() {
+ return new FileProfileComparator();
+ }
+
+ private static void addProfiles(List aProfileList, Iterator aProfilesToAdd ) {
+
+ while ( aProfilesToAdd.hasNext() ) {
+ aProfileList.add((Profile)aProfilesToAdd.next() );
+ }
+ }
+
+ private static String getRepIdFromFile( File aFile ) throws SPIException {
+ String repId;
+ String id = null;
+
+ repId = aFile.getName();
+ if ( repId.startsWith(FileProfileRepository.PREFIX ) ) {
+ try {
+ id = URLDecoder.decode(repId.substring(
+ FileProfileRepository.PREFIX.length() ),
+ System.getProperty("file.encoding"));
+ } catch (UnsupportedEncodingException e) {
+ // Shouldn't happend
+ throw new IllegalReadException(
+ IllegalReadException.FILE_READ_KEY, e);
+ }
+ }
+
+ return id;
+ }
+
+ private static boolean isRepIdInSubEntity (String repositoryId, Entity entity)
+ throws SPIException {
+ boolean result = false;
+ String entityRepositoryId = entity.getProfileRepository().getId();
+ if (entity instanceof LdapEntity) {
+ result = repositoryId.endsWith(entityRepositoryId);
+ }
+ else if (entity instanceof FileEntity) {
+ result = repositoryId.startsWith(entityRepositoryId+FileEntity.ENTITY_SEPARATOR)
+ || repositoryId.equals(entityRepositoryId);
+ }
+ return result;
+ }
+}
diff --git a/src/com/sun/apoc/spi/file/profiles/FileProfileRepository.java b/src/com/sun/apoc/spi/file/profiles/FileProfileRepository.java
new file mode 100644
index 0000000..fae97a1
--- /dev/null
+++ b/src/com/sun/apoc/spi/file/profiles/FileProfileRepository.java
@@ -0,0 +1,351 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.file.profiles;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.IllegalWriteException;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepositoryImpl;
+
+public class FileProfileRepository extends ProfileRepositoryImpl
+{
+ public final static String PREFIX = "PROFILE_REPOSITORY_";
+ public final static String DEFAULT_ID = "default";
+
+ private boolean mProfilesLoaded;
+ private File mFile;
+ boolean mReadOnly;
+ boolean mRemote;
+ URL mRootLocation;
+
+
+ public FileProfileRepository( PolicySource aPolicySource, String aId, URL aRootPath ) throws SPIException
+ {
+ mId = aId;
+ mPolicySource = aPolicySource;
+ mProfilesLoaded = false;
+ mRootLocation = aRootPath;
+
+ mReadOnly = true;
+ if ( !aRootPath.getProtocol().equals("file") ) {
+ mRemote = true;
+ } else {
+ mRemote = false;
+ try {
+ mFile = new File( new URI( mRootLocation.toString() ) );
+ } catch (URISyntaxException e) {
+ throw new IllegalReadException(
+ IllegalReadException.FILE_NAME_READ_KEY,
+ mRootLocation.toString(), e);
+ }
+
+ mReadOnly = isRepositoryReadOnly();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepositoryImpl#findProfile(java.lang.String, com.sun.apoc.spi.profiles.Applicability)
+ */
+ public Profile findProfile( String aDisplayName ) throws SPIException
+ {
+ List profileList;
+ Profile profile;
+ Profile actual;
+ Iterator it;
+
+ if ( mRemote ) {
+ throw new UnsupportedOperationException();
+ }
+ profileList = loadAllProfiles();
+ profile = null;
+ it = profileList.iterator();
+ while ( it.hasNext() ) {
+ actual = (Profile) it.next();
+ if ( actual.getDisplayName().equals(aDisplayName) ) {
+ profile = actual;
+ }
+ }
+
+ return profile;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#getProfilePriorities(com.sun.apoc.spi.profiles.Applicability)
+ */
+ public Iterator getProfilePriorities(Applicability aApplicability)
+ throws SPIException
+ {
+ List selectedProfileList;
+ List profileList;
+ Profile profile;
+ Iterator it;
+
+ profile = null;
+ if ( mRemote ) {
+ throw new UnsupportedOperationException();
+ }
+ profileList = loadAllProfiles();
+ selectedProfileList = new LinkedList();
+ it = profileList.iterator();
+ while ( it.hasNext() )
+ {
+ profile = (Profile)it.next();
+ if ( profile.getApplicability() == aApplicability )
+ {
+ selectedProfileList.add( profile );
+ }
+ }
+
+ return selectedProfileList.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#createProfile(java.lang.String, int, com.sun.apoc.spi.profiles.Applicability)
+ */
+ protected Profile createTheProfile(String aDisplayName, Applicability aApplicability, int aPriority) throws SPIException {
+ Profile profile;
+
+ if ( mReadOnly ) {
+ throw new IllegalWriteException();
+ }
+
+ profile = FileProfile.createNewProfile( this, aDisplayName, aApplicability, aPriority, mPolicySource );
+ return profile;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#destroyProfile(com.sun.apoc.spi.profiles.Profile)
+ */
+ public void deleteProfile(Profile aProfile) throws SPIException
+ {
+ String profileId;
+ profileId = aProfile.getId();
+
+ if ( mReadOnly ) {
+ throw new IllegalWriteException();
+ }
+
+ try {
+ URI fileURI;
+ File file;
+ // get the FileName
+ fileURI = new URI( FileProfile.getProfileURL(profileId, this).toString() );
+
+ file = new File( fileURI.getPath() );
+ if ( !file.delete() )
+ {
+ // Can not delete the profile
+ throw new IllegalWriteException(
+ IllegalWriteException.FILE_WRITE_KEY);
+ }
+ } catch (URISyntaxException e) {
+ throw new IllegalWriteException(
+ IllegalWriteException.FILE_WRITE_KEY, e);
+ }
+
+ aProfile = null;
+ }
+
+
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#getProfile(java.lang.String)
+ */
+ public Profile getProfile(String aId) throws SPIException
+ {
+ return FileProfile.loadProfile(aId, this, mPolicySource );
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#getProfiles(com.sun.apoc.spi.profiles.Applicability)
+ */
+ protected TreeSet getTheProfiles(Applicability aApplicability)
+ throws SPIException
+ {
+ String id;
+ Iterator it;
+ TreeSet profileApplicableList;
+ List profileList;
+ Profile profile;
+
+
+ if ( mRemote ) {
+ throw new UnsupportedOperationException();
+ }
+ profileApplicableList = new TreeSet(new FileProfileComparator());
+ profileList = loadAllProfiles();
+ it = profileList.iterator();
+ while ( it.hasNext() )
+ {
+ profile = (Profile) it.next();
+ if ( aApplicability.equals( Applicability.ALL ) ) {
+ profileApplicableList.add( profile );
+ } else if ( profile.getApplicability().equals( aApplicability ) ) {
+ profileApplicableList.add( profile );
+ }
+ }
+
+ return profileApplicableList;
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#getId()
+ */
+ public String getId()
+ {
+ return mId;
+ }
+
+ private List readProfileList() throws SPIException {
+ List profileIdList;
+ String[] fileList;
+ String fileName;
+ URL profileURL;
+ String id;
+ int end;
+
+ profileIdList = new LinkedList();
+
+ // Read the contents file and add the profile URLs to the profile list
+ String profileName;
+ fileList = mFile.list();
+ for ( int i = 0 ; i < fileList.length; i++) {
+ profileName = fileList[i];
+ // get the ID of the profile
+ end = profileName.lastIndexOf(".zip");
+ if ( end == -1 ) { continue; } // TODO log this
+ id = profileName.substring(0, end);
+ profileIdList.add( id );
+ }
+
+ return profileIdList;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#isReadOnly()
+ */
+ public boolean isReadOnly() throws SPIException
+ {
+ return mReadOnly;
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.apoc.spi.profiles.ProfileRepository#getEntity()
+ */
+ public Entity getEntity() throws SPIException
+ {
+ Entity entity = mPolicySource.getEntityProvider().getEntity(mId);
+
+ return entity;
+ }
+
+ protected String getLocation()
+ {
+ return mRootLocation.toString();
+ }
+
+ protected boolean priorityExists( int aPriority ) throws SPIException {
+ Iterator profiles = getProfiles(Applicability.ALL );
+
+ while ( profiles.hasNext() ) {
+ if ( ( (Profile)profiles.next()).getPriority() == aPriority ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected void createStorage() {
+ if ( !mFile.exists() ) {
+ mFile.mkdirs();
+ }
+ }
+
+ private List loadAllProfiles() throws SPIException
+ {
+ List profileIdList;
+ List profilesList;
+ String profileId;
+ Profile profile;
+ Iterator it;
+ String id;
+
+ profilesList = new LinkedList();
+ if ( mFile.exists() ) {
+ // only read the profiles if the directory exists
+ profileIdList = readProfileList();
+ it = profileIdList.iterator();
+ while( it.hasNext() )
+ {
+ id = (String)it.next();
+ profileId = FileProfile.createId( id, mId );
+ profile = getProfile( profileId );
+ profilesList.add( profile );
+ }
+ }
+ return profilesList;
+ }
+
+ private boolean isRepositoryReadOnly()
+ {
+ File parent;
+ parent = mFile;
+
+ do {
+ if (parent.exists() ) {
+ return !parent.canWrite();
+ }
+ } while ( (parent = parent.getParentFile() ) != null );
+
+ /* should not happend */
+ return false;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/LdapAssignmentProvider.java b/src/com/sun/apoc/spi/ldap/LdapAssignmentProvider.java
new file mode 100644
index 0000000..ff67e7a
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/LdapAssignmentProvider.java
@@ -0,0 +1,191 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.AbstractAssignmentProvider;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.environment.LdapEnvironmentMgr;
+import com.sun.apoc.spi.ldap.profiles.LdapProfile;
+import com.sun.apoc.spi.ldap.profiles.LdapProfileRepository;
+import com.sun.apoc.spi.profiles.InvalidProfileException;
+import com.sun.apoc.spi.profiles.Profile;
+/**
+ *
+ */
+public class LdapAssignmentProvider extends AbstractAssignmentProvider {
+
+ protected LdapConnectionHandler mConnection;
+ protected LdapDataStore mDataStore;
+ protected LdapEnvironmentMgr mEnvironmentMgr;
+ protected String mURL;
+
+ public LdapAssignmentProvider(PolicySource aPolicySource, String url)
+ throws SPIException {
+ mPolicySource = aPolicySource;
+ mEnvironmentMgr = new LdapEnvironmentMgr(mPolicySource.getEnvironment());
+ String mURL = url;
+ mConnection = (LdapConnectionHandler) mPolicySource.getConnectionHandler(mURL);
+ if (mConnection == null) {
+ // if mConnection is null, no Ldap connection has been
+ // established yet, the environment hasn't been checked
+ mEnvironmentMgr.checkEnvironment();
+ }
+ }
+
+ /**
+ * Opens the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws OpenConnectionException if connection error occurs
+ * @throws CloseConnectionException if connection error occurs
+ * @throws AuthenticateException if connection error occurs
+ */
+ public void open() throws SPIException {
+ if ((mConnection == null) && (mEnvironmentMgr != null)) {
+ mConnection = new LdapConnectionHandler();
+ mConnection.connect(mURL,
+ mEnvironmentMgr.getAssignmentTimeout(),
+ mEnvironmentMgr.getAssignmentAuthUser(),
+ mEnvironmentMgr.getAssignmentAuthPassword(),
+ mEnvironmentMgr);
+ if (isGSSAPIAuthentication()){
+ Object callbackHandler =
+ mEnvironmentMgr.getAssignmentCallbackHandler();
+ mConnection.authenticate(callbackHandler);
+ }
+ else {
+ mConnection.authenticate(mEnvironmentMgr.getAssignmentUser(mURL),
+ mEnvironmentMgr.getAssignmentCredentials());
+ }
+ mConnection.closeAuthorizedContext();
+
+ // store the new LdapConnectionHandler in the PolicyManager
+ mPolicySource.setConnectionHandler(mURL, mConnection);
+ }
+ mDataStore = mConnection.getDataStore();
+ }
+
+ /**
+ * Closes the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws CloseConnectionException if connection error occurs
+ */
+ public void close() throws SPIException {
+ if (mPolicySource.getConnectionHandler(mURL) != null) {
+ mPolicySource.setConnectionHandler(mURL, null);
+ }
+ mConnection.disconnect();
+ }
+
+ protected boolean isGSSAPIAuthentication() {
+ return mEnvironmentMgr.getAssignmentAuthType()
+ .equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI);
+ }
+
+ /**
+ * Assigns a profile to an entity.
+ *
+ * @param entity entity to assign the profile to
+ * @param profile profile to assign to the entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ protected void assignProfileToEntity(Entity entity, Profile profile)
+ throws SPIException {
+ if (!(profile instanceof LdapProfile)) {
+ throw new InvalidProfileException();
+ }
+ // section to ensure migration of APOC 1 Local Profiles
+ LdapProfile ldapProfile = (LdapProfile)profile;
+ if (ldapProfile.isLocal()) {
+ LdapProfileRepository rep = (LdapProfileRepository)
+ ldapProfile.getProfileRepository();
+ rep.migrateProfile(ldapProfile);
+ }
+ mDataStore.assignProfile(profile, entity);
+ }
+
+ /**
+ * Unassigns the specified profile from the entity.
+ *
+ * @param entity entity to unassign the profile to
+ * @param profile profile to unassign to the entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void unassignProfile(Entity entity, Profile profile)
+ throws SPIException {
+ if (!(profile instanceof LdapProfile)) {
+ throw new InvalidProfileException();
+ }
+ // section to ensure migration of APOC 1 Local Profiles
+ LdapProfile ldapProfile = (LdapProfile)profile;
+ if (ldapProfile.isLocal()) {
+ LdapProfileRepository rep = (LdapProfileRepository)
+ ldapProfile.getProfileRepository();
+ rep.migrateProfile(ldapProfile);
+ }
+ mDataStore.unassignProfile(profile, entity);
+ }
+
+ /**
+ * returns the profiles assigned to the entity.
+ *
+ * @param entity entity to get assigned profiles from
+ * @return Iterator on the assigned Profiles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ protected Iterator getProfilesAssignedToEntity(Entity entity)
+ throws SPIException {
+ return mDataStore.getAssignedProfiles(entity);
+ }
+
+ /**
+ * returns the entities the profile is assigned to.
+ *
+ * @param profile profile to get assigned Entities from
+ * @return Iterator on the assigned Entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getEntitiesAssignedToProfile(Profile profile)
+ throws SPIException {
+ return mDataStore.getAssignedEntities(profile);
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/LdapClientContext.java b/src/com/sun/apoc/spi/ldap/LdapClientContext.java
new file mode 100644
index 0000000..4e846e1
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/LdapClientContext.java
@@ -0,0 +1,426 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPv3;
+import netscape.ldap.factory.JSSESocketFactory;
+
+import com.netscape.sasl.Sasl;
+import com.sun.apoc.spi.AuthenticationException;
+import com.sun.apoc.spi.CloseConnectionException;
+import com.sun.apoc.spi.ConnectionSizeLimitException;
+import com.sun.apoc.spi.OpenConnectionException;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.ldap.authentication.SaslFactory;
+import com.sun.apoc.spi.ldap.entities.LdapEntity;
+
+/**
+ * Encapsulates the information related to a particular user of
+ * the API in an LDAP environment.
+ */
+public class LdapClientContext
+{
+ /** default maximum number of search results to return */
+ public static final int DEFAULT_MAX_SEARCH_RESULTS = 100;
+
+ /** character indicating that a userName contains an absolute uid **/
+ public static final char DN_INDICATOR = '=';
+
+ /**
+ * Socket factory ( with timeout ) used to build sockets
+ * for LDAPConnection
+ */
+ private static final JSSESocketFactory sSocketFactory = new JSSESocketFactory(null);
+ private static final Integer sLDAPVersion3 = new Integer(3);
+ /** Caching of insecure servers. */
+ private static Set sInsecureServers = new HashSet() ;
+ private static final int NB_INSECURE_SERVERS = 20 ;
+ /** Caching of anonymous connection pools. */
+ private static Map sAnonymousPools = new HashMap() ;
+ private static final int NB_ANONYMOUS_POOLS = 20 ;
+ /** Connection to the datastore, put here to be
+ * associated to a user and not the datastore
+ * itself, which could serve multiple users. */
+ private LDAPConnection mConnection = null ;
+ /** protocol specified in the url */
+ private String mProtocol;
+ /** name of server */
+ private String mServer;
+ /** port number for LDAP server */
+ private int mPort ;
+ /** connection timeout */
+ private int mConnectTimeout ;
+ /** maximum number of search results to return */
+ private int mMaxSearchResults = DEFAULT_MAX_SEARCH_RESULTS;
+
+ static
+ {
+ Sasl.setSaslClientFactory( new SaslFactory() );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param aServer host of the LDAP connection
+ * @param aPort port of the LDAP connection
+ * @param aTimeout timeout to initiate the LDAP connection
+ */
+ public LdapClientContext(String aProtocol, String aServer,
+ int aPort, int aTimeout) {
+ mProtocol = aProtocol;
+ mServer = aServer;
+ mPort = aPort;
+ mConnectTimeout = aTimeout;
+ }
+
+ /**
+ * creates and opens an Ldap connection,
+ * and stores it as mConnection
+ * The connection is authenticated using aUserDN and aPwd.
+ * If aUserDN is null, empty or Anonymous,
+ * it opens an anonymous connection.
+ *
+ * @param aUserDN full DN of the user for the authentication
+ * @param aPwd password for the authentication
+ * @throws SPIException if error occurs
+ * @throws OpenConnectionException if error occurs
+ * @throws AuthenticateException if error occurs
+ */
+ public void connect(String aUserDN, char[] aPwd)
+ throws SPIException {
+ try {
+ if (isAnonymous(aUserDN, aPwd)) {
+ mConnection = getAnonymousConnection(mServer, mPort);
+ if (mConnection == null) {
+ mConnection = prepareConnection();
+ mConnection.authenticate(null,null);
+ addAnonymousConnection(mServer, mPort, mConnection);
+ }
+ } else {
+ mConnection = prepareConnection();
+ mConnection.authenticate(aUserDN, new String(aPwd));
+ }
+ } catch (LDAPException ldape) {
+ throw new AuthenticationException(
+ getConnectionURL(), aUserDN, ldape);
+ }
+ }
+
+ /**
+ * creates and opens an Ldap connection,
+ * and stores it as mConnection
+ * The full DN corresponding to the username is
+ * retrieved from the root Organization using the
+ * authorized connection.
+ * The connection is authenticated using the full DN and aPwd.
+ * If aUserName is null, empty or Anonymous,
+ * it opens an anonymous connection.
+ *
+ * @param aUserName user name
+ * @param aCredentials user credentials
+ * @param aRootOrg the RootOrganization
+ * @param aAuthorized authorized connection to the datasource
+ * @throws <code>SPIException</code> if
+ * an error occurs
+ * @throws OpenConnectionException if error occurs
+ * @throws AuthenticateException if error occurs
+ */
+ public void authenticate(String aUserName, char[] aCredentials,
+ Organization aRootOrg,
+ LdapClientContext aAuthorized)
+ throws SPIException {
+ String userId = null;
+ if ((aUserName != null) && (aUserName.length() != 0)
+ && (!aUserName.equalsIgnoreCase(
+ EnvironmentConstants.LDAP_USER_ANONYMOUS))) {
+ if (aUserName.indexOf(DN_INDICATOR) >= 0) {
+ userId = aUserName;
+ }
+ else {
+ Entity userEntity = null;
+ LdapClientContext rootOrgContext =
+ ((LdapEntity)aRootOrg).getContext();
+ ((LdapEntity)aRootOrg).setContext(aAuthorized);
+ Iterator entities = aRootOrg.findUsers(aUserName, true);
+ ((LdapEntity)aRootOrg).setContext(rootOrgContext);
+ if (entities.hasNext()) {
+ userEntity = (Entity)entities.next();
+ }
+ if (userEntity == null) {
+ throw new AuthenticationException(
+ getConnectionURL(), aUserName);
+ }
+ userId = ((LdapEntity)userEntity).getLocation();
+ }
+ }
+ connect(userId, aCredentials);
+ }
+
+ /**
+ * creates and opens an Ldap connection,
+ * and stores it as mConnection
+ * The connection is authenticated using SASL
+ * and the provided callback handler.
+ *
+ * @param aCallbackHandler callback handler to use
+ * for authentication
+ * @throws <code>SPIException</code> if
+ * an error occurs
+ * @throws OpenConnectionException if error occurs
+ * @throws AuthenticateException if error occurs
+ */
+ public void authenticate(Object aCallbackHandler)
+ throws SPIException {
+ try {
+ mConnection = prepareConnection();
+ mConnection.authenticate(null, SaslFactory.sMechs,
+ null, aCallbackHandler);
+ } catch (LDAPException ldape) {
+ throw new AuthenticationException(
+ getConnectionURL(), ldape);
+ }
+ }
+
+ /**
+ * Close the context, ie release all resources associated with
+ * one.
+ *
+ * @throws <code>SPIException</code> if LDAP
+ * error occurs
+ * @throws CloseConnectionException if error occurs
+ */
+ public void close() {
+ if ( mConnection != null )
+ {
+ if ( ! closeAnonymousConnection(mServer, mPort, mConnection ) )
+ {
+ closeConnection( mConnection );
+ }
+ mConnection = null;
+ }
+ }
+
+ private void closeConnection( LDAPConnection inConnection )
+ {
+ if ( inConnection.isConnected() )
+ {
+ new LDAPConnectionDisconnector( inConnection ).start();
+ }
+ }
+
+ /**
+ * creates an Ldap connection and connects it to the
+ * mServer and mPort.
+ * @return the connection created
+ * @throws SPIException
+ * @throws OpenConnectionException if error occurs
+ */
+ private LDAPConnection prepareConnection () throws SPIException {
+ LDAPConnection connection = null;
+ if (!isInsecureServer(mServer, mPort)) {
+ try
+ {
+ // First try an SSL connection
+ connection = new LDAPConnection(sSocketFactory);
+ setupConnection(connection);
+ }
+ catch(LDAPException ldape)
+ {
+ // OTHER can be thrown if an error occurred during SSL handshake
+ // CONNECT_ERROR can be thrown if LDAP is not configured for SSL
+ if ( ((ldape.getLDAPResultCode() == LDAPException.OTHER)
+ || (ldape.getLDAPResultCode() == LDAPException.CONNECT_ERROR))
+ && (!mProtocol.equalsIgnoreCase(EnvironmentConstants.LDAPS_URL_PROTOCOL)) ) {
+ addInsecureServer(mServer, mPort) ;
+ closeConnection( connection );
+ connection = null ;
+ }
+ else {
+ throw new OpenConnectionException(
+ getConnectionURL(), ldape);
+ }
+ }
+ }
+ if (connection == null ) {
+ try {
+ //Try a non SSL connection
+ connection = new LDAPConnection();
+ setupConnection(connection);
+ }
+ catch (LDAPException ldape2) {
+ closeConnection( connection );
+ connection = null;
+ throw new OpenConnectionException(
+ getConnectionURL(), ldape2);
+ }
+ }
+ return connection;
+ }
+
+ private void setupConnection (LDAPConnection connection)
+ throws LDAPException{
+ try {
+ // Set the protocol version to v3 (or at least try)
+ connection.setOption(LDAPv3.PROTOCOL_VERSION, sLDAPVersion3) ;
+ connection.setOption(LDAPv3.REFERRALS, Boolean.TRUE) ;
+ }
+ catch (LDAPException ignored) { }
+ connection.setConnectTimeout(mConnectTimeout);
+ connection.connect(mServer, mPort);
+ }
+
+ /**
+ * Returns the connection object to be used
+ * to access the datastore.
+ *
+ * @return connection to the datastore
+ */
+ public LDAPConnection getConnection() {
+ return mConnection;
+ }
+
+ /**
+ * Returns a String describing the server as an URL
+ *
+ * @return ldap://[hostname]:[port]
+ */
+ public String getConnectionURL() {
+ return mProtocol+"://"+mServer+":"+String.valueOf(mPort);
+ }
+
+ /**
+ * Sets the maximum number of search results returned by the Ldap connection
+ *
+ * @param sizeLimit the maximum number of results
+ * @throws SPIException if error occurs when setting the limit
+ */
+ public void setConnectionSizeLimit(int sizeLimit) throws SPIException {
+ try {
+ mConnection.setOption(LDAPv3.SIZELIMIT, new Integer(sizeLimit));
+ mMaxSearchResults = sizeLimit;
+ }
+ catch (LDAPException ldape) {
+ throw new ConnectionSizeLimitException(
+ getConnectionURL(), sizeLimit, ldape);
+ }
+ }
+
+ /**
+ * Get the maximum number of search results returned by the Ldap connection
+ * @return the maximum number of results
+ */
+ public int getConnectionSizeLimit() {
+ return mMaxSearchResults;
+ }
+
+ private static String getServerPortKey(String aServer, int aPort) {
+ return aServer + ":" + aPort ;
+ }
+ private static boolean isInsecureServer(String aServer, int aPort) {
+ return sInsecureServers.contains(getServerPortKey(aServer, aPort)) ;
+ }
+ private static void addInsecureServer(String aServer, int aPort) {
+ if (sInsecureServers.size() < NB_INSECURE_SERVERS) {
+ sInsecureServers.add(getServerPortKey(aServer, aPort)) ;
+ }
+ }
+ private static LDAPConnection getAnonymousConnection(String aServer,
+ int aPort) {
+ LdapConnectionPool pool =
+ (LdapConnectionPool) sAnonymousPools.get(getServerPortKey(aServer,
+ aPort)) ;
+
+ return pool != null ? pool.getConnection() : null ;
+ }
+ private static void addAnonymousConnection(String aServer, int aPort,
+ LDAPConnection aConnection) {
+ LdapConnectionPool pool = null ;
+
+ synchronized (sAnonymousPools) {
+ pool = (LdapConnectionPool) sAnonymousPools.get(
+ getServerPortKey(aServer, aPort)) ;
+
+ if (pool == null && sAnonymousPools.size() < NB_ANONYMOUS_POOLS) {
+ pool = new LdapConnectionPool(aServer, aPort) ;
+ sAnonymousPools.put(getServerPortKey(aServer, aPort), pool) ;
+ }
+ }
+ if (pool != null) { pool.addConnection(aConnection) ; }
+ }
+ private static boolean closeAnonymousConnection(
+ String aServer, int aPort,
+ LDAPConnection aConnection) {
+ LdapConnectionPool pool =
+ (LdapConnectionPool) sAnonymousPools.get(getServerPortKey(aServer,
+ aPort)) ;
+
+ return pool != null ? pool.closeConnection(aConnection) : false ;
+ }
+ // If the user or the password are null or empty,
+ // or user is anonymous,
+ // this amounts to an anonymous connection
+ private static boolean isAnonymous(String aUser, char[] aCredentials) {
+ return ( (aCredentials == null) || (aCredentials.length == 0)
+ || (aUser == null) || (aUser.length() == 0)
+ || aUser.equalsIgnoreCase(EnvironmentConstants.LDAP_USER_ANONYMOUS) );
+ }
+ class LDAPConnectionDisconnector extends Thread
+ {
+ LDAPConnection mConnection;
+
+ LDAPConnectionDisconnector( LDAPConnection inConnection ) {
+ mConnection = inConnection;
+ }
+
+ public void run() {
+ try {
+ mConnection.disconnect();
+ }
+ catch( Exception theException ){}
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/LdapConnectionHandler.java b/src/com/sun/apoc/spi/ldap/LdapConnectionHandler.java
new file mode 100644
index 0000000..275a294
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/LdapConnectionHandler.java
@@ -0,0 +1,310 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap;
+
+import java.util.Hashtable;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.environment.ConfigurationProvider;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.environment.EnvironmentMgr;
+import com.sun.apoc.spi.file.environment.FileConfigurationProvider;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.ldap.environment.LdapConfigurationProvider;
+import com.sun.apoc.spi.ldap.environment.LdapEnvironmentMgr;
+import com.sun.apoc.spi.util.MetaConfiguration;
+
+/**
+ * manages the objects giving access to the Ldap data
+ */
+public class LdapConnectionHandler {
+
+ private String mConnectionUrl = null;
+ private LdapClientContext mAuthorizedContext = null;
+ private LdapClientContext mAuthenticatedContext = null;
+ private LdapDataStore mDataStore = null;
+ private Organization mRootOrganization = null;
+ private Domain mRootDomain = null;
+ private int mMaxSearchResults;
+
+ /**
+ * Opens an authorized connection to the Ldap server
+ *
+ * @param host name of the Ldap server to connect to
+ * @param port port of the Ldap server to connect to
+ * @param timeout timeout on the connection to open
+ * @param authUser authorized user on the Ldap server
+ * @param authPwd password of the authorised user
+ * @throws SPIException if error occurs
+ */
+ public void openAuthorizedContext(
+ String protocol, String host, int port, int timeout,
+ String authUser, char[] authPwd) throws SPIException {
+ if (mAuthorizedContext == null) {
+ mAuthorizedContext = new LdapClientContext(protocol, host, port, timeout);
+ mAuthorizedContext.connect(authUser, authPwd);
+ mAuthorizedContext.setConnectionSizeLimit(mMaxSearchResults);
+ }
+ }
+
+ /**
+ * Closes the current authorized connection
+ * @throws SPIException
+ */
+ public void closeAuthorizedContext() throws SPIException {
+ if (mAuthorizedContext != null) {
+ mAuthorizedContext.close();
+ mAuthorizedContext = null;
+ }
+ }
+
+ /**
+ * Created an LdapDataStore object using the authorized connection
+ * already opened
+ * @param baseEntry base entry on the Ldap server
+ * @throws SPIException is error occurs
+ */
+ public void createDataStore(String baseEntry) throws SPIException {
+ mDataStore = new LdapDataStore(baseEntry, mAuthorizedContext);
+ }
+
+ /**
+ * Opens an authorized connection to the Ldap server,
+ * opens a second connection to the Ldap server, to be authenticated,
+ * and prepares the internal datastructures
+ *
+ * @param url url describing the Ldap connection to make
+ * @param timeout timeout on the connection to open
+ * @param authUser authorized user on the Ldap server
+ * @param authPwd password of the authorised user
+ * @param envMgr environment manager, used to get the
+ * parameters describing the access to
+ * the MetaConfiguration
+ * @throws SPIException if error occurs
+ */
+ public void connect(String url, int timeout, String authUser,
+ char[] authPwd, LdapEnvironmentMgr envMgr)
+ throws SPIException {
+ mConnectionUrl = url;
+ mMaxSearchResults = envMgr.getSearchResultSizeLimit();
+ String protocol = LdapEnvironmentMgr.getProtocolFromURL(mConnectionUrl);
+ String host = LdapEnvironmentMgr.getHostFromURL(mConnectionUrl);
+ int port = LdapEnvironmentMgr.getPortFromURL(mConnectionUrl);
+ String baseEntry =
+ LdapEnvironmentMgr.getBaseEntryFromURL(mConnectionUrl);
+ openAuthorizedContext(protocol, host, port, timeout, authUser, authPwd);
+ createDataStore(baseEntry);
+ MetaConfiguration metaConfData = getMetaConfiguration(envMgr);
+ mDataStore.setVersion(metaConfData);
+ LdapEntityMapping entityMapping = new LdapEntityMapping(metaConfData);
+ mAuthenticatedContext = new LdapClientContext(protocol, host, port, timeout);
+ mRootOrganization = mDataStore.createRootOrganization(
+ entityMapping, mAuthorizedContext, mAuthenticatedContext);
+ mRootDomain = mDataStore.createRootDomain(
+ entityMapping, mAuthorizedContext, mAuthenticatedContext);
+ }
+
+ /**
+ * Authenticate the second connection to the Ldap server
+ * using the username and credentials
+ *
+ * @param userName user name of the user to authenticate
+ * @param credentials credentials of the user
+ * @throws SPIException if error occurs
+ */
+ public void authenticate(String userName, char[] credentials)
+ throws SPIException {
+ mAuthenticatedContext.authenticate(userName, credentials,
+ mRootOrganization, mAuthorizedContext);
+ mAuthenticatedContext.setConnectionSizeLimit(mMaxSearchResults);
+ }
+
+ /**
+ * Authenticate the second connection to the Ldap server
+ * using GSSAPI and the callbackHandler
+ *
+ * @param callbackHandler callbackHandler for the
+ * GSSAPI authentication
+ * @throws SPIException if error occurs
+ */
+ public void authenticate(Object callbackHandler)
+ throws SPIException {
+ mAuthenticatedContext.authenticate(callbackHandler);
+ mAuthenticatedContext.setConnectionSizeLimit(mMaxSearchResults);
+ }
+
+ /**
+ * closes the authenticated (second) connection
+ * @throws SPIException
+ */
+ public void disconnect() throws SPIException {
+ if (mAuthenticatedContext != null) {
+ mAuthenticatedContext.close();
+ }
+ }
+
+ /**
+ * Connects to the specified datasource
+ * to get the Ldap Metaconfiguration data
+ *
+ * @param envMgr EnvironmentManager providing access to parameters
+ * defining the Metaconfiguration datasource
+ * @return the metaconfiguration data
+ * @throws SPIException if error occurs
+ */
+ public MetaConfiguration getMetaConfiguration(LdapEnvironmentMgr envMgr)
+ throws SPIException {
+ Hashtable metaConfData = envMgr.getMetaConfiguration();
+ if (metaConfData == null) {
+ metaConfData = new Hashtable();
+ ConfigurationProvider metaConfProvider = null;
+ String urls[] = envMgr.getMetaConfURLs();
+ for (int i=0; i<urls.length; i++) {
+ String url = urls[i];
+ try {
+ String protocol = EnvironmentMgr.getProtocolFromURL(url);
+ // Ldap
+ if (envMgr.isLdapProtocol(protocol)) {
+ metaConfProvider = getLdapMetaConfProvider(envMgr, url);
+ } // File or Http
+ else if (envMgr.isFileProtocol(protocol)) {
+ metaConfProvider = getFileMetaConfProvider(envMgr, url);
+ }
+ if (metaConfProvider == null) {
+ continue;
+ }
+ else {
+ metaConfData = metaConfProvider.loadData();
+ }
+ } catch (SPIException spie) {
+ // if an exception is thrown,
+ // the connection couldn't be opened correctly
+ // so continue the loop to the next URL
+ if (metaConfProvider != null) {
+ metaConfProvider = null;
+ }
+ // if last iteration of the loop, throw the exception
+ if (i == (urls.length-1)) {
+ throw spie;
+ }
+ continue;
+ }
+ // no exception thrown, the connection was successful,
+ // no need to continue the loop further
+ break;
+ }
+ }
+ return new MetaConfiguration(metaConfData);
+ }
+
+ private LdapConfigurationProvider getLdapMetaConfProvider(
+ LdapEnvironmentMgr envMgr, String url)
+ throws SPIException {
+ LdapConfigurationProvider metaConfProvider = null;
+ String[] attributesToGet = new String[] {LdapDataStore.ORG_MAP_KEY,
+ LdapDataStore.LDAP_ATTR_MAP_KEY};
+ if (url.equals(mConnectionUrl)) {
+ metaConfProvider = new LdapConfigurationProvider(
+ url, mAuthorizedContext, mDataStore, attributesToGet);
+ }
+ else {
+ LdapConnectionHandler metaConfConnection = new LdapConnectionHandler();
+ metaConfConnection.openAuthorizedContext(
+ LdapEnvironmentMgr.getProtocolFromURL(url),
+ LdapEnvironmentMgr.getHostFromURL(url),
+ LdapEnvironmentMgr.getPortFromURL(url),
+ envMgr.getMetaConfTimeout(),
+ envMgr.getMetaConfAuthUser(),
+ envMgr.getMetaConfAuthPassword());
+ metaConfConnection.createDataStore(
+ LdapEnvironmentMgr.getBaseEntryFromURL(url));
+ metaConfProvider = new LdapConfigurationProvider(
+ url, metaConfConnection.getAuthorizedContext(),
+ metaConfConnection.getDataStore(),
+ attributesToGet);
+ metaConfConnection.closeAuthorizedContext();
+ }
+ return metaConfProvider;
+ }
+
+ private FileConfigurationProvider getFileMetaConfProvider(
+ LdapEnvironmentMgr envMgr, String url)
+ throws SPIException {
+ FileConfigurationProvider metaConfProvider = null;
+ StringBuffer rootURL = new StringBuffer(url);
+ if (!url.endsWith(EnvironmentConstants.URL_SEPARATOR)) {
+ rootURL.append(EnvironmentConstants.URL_SEPARATOR);
+ }
+ StringBuffer orgMapFile = new StringBuffer();
+ orgMapFile.append(rootURL).append(EnvironmentConstants.ORG_MAP_FILE);
+ String[] filesToGet = new String[] {orgMapFile.toString()};
+ metaConfProvider = new FileConfigurationProvider(filesToGet);
+ return metaConfProvider;
+ }
+
+ /**
+ * @return Returns the mAuthenticatedContext.
+ */
+ public LdapClientContext getAuthenticatedContext() {
+ return mAuthenticatedContext;
+ }
+ /**
+ * @return Returns the mAuthorizedContext.
+ */
+ public LdapClientContext getAuthorizedContext() {
+ return mAuthorizedContext;
+ }
+ /**
+ * @return Returns the mDataStore.
+ */
+ public LdapDataStore getDataStore() {
+ return mDataStore;
+ }
+ /**
+ * @return Returns the mRootDomain.
+ */
+ public Domain getRootDomain() {
+ return mRootDomain;
+ }
+ /**
+ * @return Returns the mRootOrganization.
+ */
+ public Organization getRootOrganization() {
+ return mRootOrganization;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/LdapConnectionPool.java b/src/com/sun/apoc/spi/ldap/LdapConnectionPool.java
new file mode 100644
index 0000000..d0f8069
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/LdapConnectionPool.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap ;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+
+import netscape.ldap.LDAPConnection;
+
+public class LdapConnectionPool {
+ private Set mUsedConnections = new HashSet() ;
+ private Stack mFreeConnections = new Stack() ;
+ private String mServer = null ;
+ private int mPort = 389 ;
+
+ private static final int MAX_CONN = 50 ;
+
+ public LdapConnectionPool(String aServer, int aPort) {
+ mServer = aServer ;
+ mPort = aPort ;
+ }
+ public synchronized LDAPConnection getConnection() {
+ LDAPConnection retCode = null ;
+
+ if (!mFreeConnections.empty()) {
+ retCode = (LDAPConnection) mFreeConnections.pop() ;
+ if (retCode.isConnected()) { mUsedConnections.add(retCode) ; }
+ else { retCode = null ; }
+ }
+ return retCode ;
+ }
+ public synchronized void addConnection(LDAPConnection aConnection) {
+ if (mUsedConnections.size() + mFreeConnections.size() < MAX_CONN) {
+ mUsedConnections.add(aConnection) ;
+ }
+ }
+ public synchronized boolean closeConnection(LDAPConnection aConnection) {
+ if (mUsedConnections.contains(aConnection)) {
+ mUsedConnections.remove(aConnection) ;
+ mFreeConnections.push(aConnection) ;
+ return true ;
+ }
+ return false ;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/LdapProviderFactory.java b/src/com/sun/apoc/spi/ldap/LdapProviderFactory.java
new file mode 100644
index 0000000..11aa9db
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/LdapProviderFactory.java
@@ -0,0 +1,82 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap;
+
+import com.sun.apoc.spi.AssignmentProvider;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.Provider;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.EntityTreeProvider;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.ldap.entities.LdapDomainProvider;
+import com.sun.apoc.spi.ldap.entities.LdapOrganizationProvider;
+import com.sun.apoc.spi.ldap.profiles.LdapProfileProvider;
+import com.sun.apoc.spi.profiles.ProfileProvider;
+
+/**
+ * Class for providing LDAP-type Providers.
+ */
+public class LdapProviderFactory {
+
+ public LdapProviderFactory() {
+ }
+
+ /**
+ * Returns the requested type of <code>Provider</code> object .
+ *
+ * @param url the url specifying the provider data source
+ * @param aProviderClass the type of <code>Provider</code> object
+ * @param aPolicySource the <code>PolicySource</code> that owns these providers
+ * @return <code>Provider</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ static public Provider get(String url, Class aProviderClass, PolicySource aPolicySource) throws SPIException {
+ Provider provider = null;
+ String sEntityType = aPolicySource.getName();
+ if (aProviderClass == EntityTreeProvider.class) {
+ if (sEntityType.equals(EnvironmentConstants.HOST_SOURCE)) {
+ provider = new LdapDomainProvider(aPolicySource, url);
+ } else if (sEntityType.equals(EnvironmentConstants.USER_SOURCE)) {
+ provider = new LdapOrganizationProvider(aPolicySource, url);
+ }
+ } else if (aProviderClass == AssignmentProvider.class) {
+ provider = new LdapAssignmentProvider(aPolicySource, url);
+ } else if (aProviderClass == ProfileProvider.class) {
+ provider = new LdapProfileProvider(aPolicySource, url);
+ }
+ return provider;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/authentication/LdapSaslGSSAPICallback.java b/src/com/sun/apoc/spi/ldap/authentication/LdapSaslGSSAPICallback.java
new file mode 100644
index 0000000..df2223b
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/authentication/LdapSaslGSSAPICallback.java
@@ -0,0 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only (\"GPL\") or
+ * the Common Development and Distribution License(\"CDDL\")
+ * (collectively, the \"License\"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * \"Portions Copyrighted [year] [name of copyright owner]\"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding \"[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license.\" If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.authentication;
+
+public class LdapSaslGSSAPICallback extends SaslGSSAPICallback
+{
+ private static final String sServiceName = "ldap";
+
+ public LdapSaslGSSAPICallback( String inHostName )
+ throws IllegalArgumentException
+ {
+ super( inHostName, sServiceName );
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/authentication/SaslFactory.java b/src/com/sun/apoc/spi/ldap/authentication/SaslFactory.java
new file mode 100644
index 0000000..e3422ce
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/authentication/SaslFactory.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.authentication;
+
+import java.util.Hashtable;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import com.netscape.sasl.SaslClient;
+import com.netscape.sasl.SaslClientFactory;
+import com.netscape.sasl.SaslException;
+
+
+public class SaslFactory implements SaslClientFactory
+{
+ public static final String sMechs[] = { SaslMechanism.sMech };
+
+ public SaslClient createSaslClient( String[] inMechs,
+ String inAuthorizationId,
+ String inProtocol,
+ String inServerName,
+ Hashtable inProps,
+ CallbackHandler inCallbackHandler )
+ throws SaslException
+ {
+ return new SaslMechanism( inServerName, inCallbackHandler );
+ }
+
+ public String[] getMechanismNames() { return sMechs; }
+}
diff --git a/src/com/sun/apoc/spi/ldap/authentication/SaslGSSAPICallback.java b/src/com/sun/apoc/spi/ldap/authentication/SaslGSSAPICallback.java
new file mode 100644
index 0000000..4dcca69
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/authentication/SaslGSSAPICallback.java
@@ -0,0 +1,73 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only (\"GPL\") or
+ * the Common Development and Distribution License(\"CDDL\")
+ * (collectively, the \"License\"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * \"Portions Copyrighted [year] [name of copyright owner]\"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding \"[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license.\" If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.authentication;
+
+public class SaslGSSAPICallback implements javax.security.auth.callback.Callback
+{
+ private String mHostName;
+ private String mServiceName;
+ private byte[] mChallenge;
+ private byte[] mResponse;
+
+ public SaslGSSAPICallback( String inHostName, String inServiceName )
+ throws IllegalArgumentException
+ {
+ if ( inHostName == null ||
+ inHostName.length() == 0 ||
+ inServiceName == null ||
+ inServiceName.length() == 0 )
+ {
+ throw new IllegalArgumentException();
+ }
+ mHostName = inHostName;
+ mServiceName = inServiceName;
+ }
+
+ public byte[] getChallenge() { return mChallenge; }
+ public String getHostname() { return mHostName; }
+ public byte[] getResponse() { return mResponse; }
+ public String getServiceName() { return mServiceName; }
+
+ public void setChallenge( byte[] inChallenge )
+ {
+ mChallenge = inChallenge;
+ }
+
+ public void setResponse( byte[] inResponse )
+ {
+ mResponse = inResponse;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/authentication/SaslMechanism.java b/src/com/sun/apoc/spi/ldap/authentication/SaslMechanism.java
new file mode 100644
index 0000000..7664cc5
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/authentication/SaslMechanism.java
@@ -0,0 +1,118 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.authentication;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+
+import com.netscape.sasl.SaslClient;
+import com.netscape.sasl.SaslException;
+
+
+public class SaslMechanism implements SaslClient
+{
+ public static final String sMech = "GSSAPI";
+
+ private static short sSequenceMax = 3;
+ private short mSequence = 0;
+ private CallbackHandler mHandler;
+ private LdapSaslGSSAPICallback[] mCallbacks =
+ new LdapSaslGSSAPICallback[ 1 ];
+
+ public SaslMechanism( String inHostName, CallbackHandler inHandler )
+ throws IllegalArgumentException
+ {
+ if ( inHandler == null )
+ {
+ throw new IllegalArgumentException();
+ }
+ mCallbacks[ 0 ] = new LdapSaslGSSAPICallback( inHostName );
+ mHandler = inHandler;
+ }
+
+ public String getMechanismName() { return sMech; }
+
+ public InputStream getInputStream( InputStream inInputStream )
+ throws java.io.IOException
+ { return inInputStream; }
+
+ public OutputStream getOutputStream( OutputStream inOutputStream )
+ throws java.io.IOException
+ { return inOutputStream; }
+
+ public byte[] createInitialResponse()
+ throws SaslException
+ {
+ try
+ {
+ mHandler.handle( ( Callback[] )mCallbacks );
+ ++ mSequence;
+ return mCallbacks[ 0 ].getResponse();
+ }
+ catch( Exception theException )
+ {
+ throw new SaslException();
+ }
+ }
+
+ public byte[] evaluateChallenge( byte[] inChallenge )
+ throws SaslException
+ {
+ try
+ {
+ if ( isComplete() )
+ {
+ return null;
+ }
+ else
+ {
+ mCallbacks[ 0 ].setChallenge( inChallenge );
+ mHandler.handle( ( Callback[] )mCallbacks );
+ ++ mSequence;
+ return mCallbacks[ 0 ].getResponse();
+ }
+ }
+ catch( Exception theException )
+ {
+ throw new SaslException();
+ }
+ }
+
+ public boolean isComplete() { return mSequence >= sSequenceMax; }
+}
diff --git a/src/com/sun/apoc/spi/ldap/datastore/LdapDataStore.java b/src/com/sun/apoc/spi/ldap/datastore/LdapDataStore.java
new file mode 100644
index 0000000..92772a6
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/datastore/LdapDataStore.java
@@ -0,0 +1,3339 @@
+ /*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.datastore;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import netscape.ldap.LDAPAttribute;
+import netscape.ldap.LDAPAttributeSet;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPEntry;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPModification;
+import netscape.ldap.LDAPModificationSet;
+import netscape.ldap.LDAPSearchResults;
+import netscape.ldap.LDAPv2;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.IllegalWriteException;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.NoSuchEntityException;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.entities.LdapDomain;
+import com.sun.apoc.spi.ldap.entities.LdapEntity;
+import com.sun.apoc.spi.ldap.entities.LdapEntityType;
+import com.sun.apoc.spi.ldap.entities.LdapNode;
+import com.sun.apoc.spi.ldap.entities.LdapOrganization;
+import com.sun.apoc.spi.ldap.entities.LdapRole;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.ldap.policies.LdapPolicy;
+import com.sun.apoc.spi.ldap.profiles.LdapProfile;
+import com.sun.apoc.spi.ldap.profiles.LdapProfileComparator;
+import com.sun.apoc.spi.ldap.profiles.LdapProfileRepository;
+import com.sun.apoc.spi.ldap.util.Timestamp;
+import com.sun.apoc.spi.policies.NoSuchPolicyException;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.policies.PolicyInfo;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.InvalidPriorityException;
+import com.sun.apoc.spi.profiles.InvalidProfileException;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileImpl;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+import com.sun.apoc.spi.profiles.ProfileRepositoryImpl;
+import com.sun.apoc.spi.util.BooleanReturnValue;
+import com.sun.apoc.spi.util.MetaConfiguration;
+
+/**
+ * Handles the access to data stored in an LDAP storage.
+ */
+public class LdapDataStore
+{
+ /** set length for buffers used for building strings */
+ public static final int BUFFER_LENGTH = 200;
+ /** Constant indicating recursive search required */
+ public static final boolean RECURSIVE_SEARCH = true;
+ /** Constant indicating non-recursive search required */
+ public static final boolean NON_RECURSIVE_SEARCH = false;
+
+ private float versionNb = 1.0f;
+ private boolean isVersion1 = true;
+ private LdapOrganization mRootOrganization;
+ private LdapDomain mRootDomain;
+ /** service entry buffer*/
+ public StringBuffer mServiceEntryDNBuf = null ;
+ /** buffer for root service entry */
+ public StringBuffer mRootServiceEntryDNBuf =
+ new StringBuffer(BUFFER_LENGTH);
+
+ /** key to Version in MetaConfiguration */
+ static final String VERSION_KEY = "ApocVersion";
+
+ /** strings describing elements of the service entry */
+ public static final String SERVICES = "services";
+ public static final String SERVICE_APOC = "ApocService";
+ public static final String SERVICE_ORG_CONFIG = "OrganizationConfig";
+ public static final String SERVICE_VERSION = "1.0";
+ public static final String SERVICE_DEFAULT = "default";
+ public static final String SERVICE_REGISTRY = "ApocRegistry";
+ /** number of service elements */
+ public static final int NUMBER_OF_SERVICE_MAPPING_ELEMENTS = 6;
+ /** Array describing the object classes of the service entry. */
+ public static ServiceMapping [] SERVICE_MAPPING_ELEMENTS =
+ new ServiceMapping [NUMBER_OF_SERVICE_MAPPING_ELEMENTS] ;
+ /** mapping for object class and attribute for profile container */
+ private static EntryMapping CONTAINER_MAPPING;
+ /** mapping for object class and attribute for profile */
+ private static EntryMapping PROFILE_MAPPING;
+ /** mapping for object class and attribute for policy */
+ private static EntryMapping POLICY_MAPPING;
+ /** Key used to store DN value in search results */
+ public static final String DN_KEY = "DN";
+ /** name for an LDAP object class */
+ public static final String LDAP_OBJCLASS = "objectclass" ;
+ /** name for the LDAP organizational unit object class */
+ public static final String ORG_UNIT_OBJCLASS = "organizationalunit" ;
+ /** name for the LDAP organizational unit naming attribute */
+ public static final String ORG_UNIT_NAMING_ATTR = "ou" ;
+ public static final String CONFIG_NAMING_ATTR= ORG_UNIT_NAMING_ATTR + "=";
+ /** name of the sunservice object class */
+ private static final String SUNSERVICE_OBJCLASS = "sunservice";
+ /** name of the sunservice component object class */
+ public static final String SUNSERVICE_COMPONENT_OBJCLASS =
+ "sunservicecomponent";
+ /** name of the attribute used to store id value */
+ private static final String SUNSERVICEID_ATTR = "sunserviceid";
+ /** value of the sunserviceid for profiles */
+ private static final String SUNSERVICEID_PROFILE = "ApocPolicyGroup";
+ /** value of the sunserviceid for policies */
+ private static final String SUNSERVICEID_POLICY = "ApocPolicy";
+ /** name of the attribute used to store key/value data */
+ public static final String KEYVALUE_ATTR = "sunkeyvalue";
+ /** name of the attribute used to store profile priority */
+ private static final String PRIORITY_ATTR = "sunsmspriority";
+ /** name of attribute storing time of last modification of entry */
+ public static final String MODIFY_TIMESTAMP_ATTR =
+ "modifytimestamp";
+ /** name of attribute storing DN of last modifier of entry */
+ private static final String MODIFY_AUTHOR_ATTR =
+ "modifiersname";
+ /** name of applicability key for the sunkeyvalue attribute */
+ private static final String APPLICABILITY_KEY = "applicability=";
+ /** name of key for xmlblobs for the sunkeyvalue attribute */
+ private static final String APOC_BLOB_KEY = "APOCBlob=";
+ /** name of display name key for the sunkeyvalue attribute */
+ private static final String DISPLAY_NAME_KEY = "displayname=";
+ /** name of organization mapping key for the sunkeyvalue attribute */
+ public static final String ORG_MAP_KEY = "organizationalmapping=";
+ /** name of user profile mapping key for the sunkeyvalue attribute */
+ public static final String LDAP_ATTR_MAP_KEY = "ldapattributemapping=";
+ /** name of key for assigning profiles to an entity using
+ the sunkeyvalue attribute */
+ private static final String ASSIGNED_KEY = "assigned=";
+ /** name of key for adding comment to profile using
+ the sunkeyvalue attribute */
+ private static final String COMMENT_KEY = "comment=";
+ /** value of keyvalue attribute storing profile applicability
+ with value user */
+ private static final String USER_PROFILE_USE_VALUE =
+ APPLICABILITY_KEY + Applicability.USER;
+ /** value of keyvalue attribute storing profile applicability
+ with value host */
+ private static final String HOST_PROFILE_USE_VALUE =
+ APPLICABILITY_KEY + Applicability.HOST;
+ /** PolicyIdParser object */
+ PolicyIdParser mPolicyIdParser = new PolicyIdParser();
+ /** wildcard for LDAP searchs */
+ public static final String LDAP_WILDCARD = "*";
+ /** LDAP repository base DN. */
+ private String mBaseDN = null ;
+ /** Version of the base DN as retrieved from the LDAP server. **/
+ private String mRootDN = null ;
+
+
+ /** class for mapping entry to required objectclass
+ and attribute */
+ static class EntryMapping {
+ String mObjectClass = null;
+ LDAPAttribute mServiceIdAttr = null;
+
+ EntryMapping(String aObjectClass) {
+ mObjectClass = aObjectClass;
+ }
+
+ EntryMapping(String aObjectClass, String aServiceIdValue) {
+ mObjectClass = aObjectClass;
+ mServiceIdAttr = new LDAPAttribute(SUNSERVICEID_ATTR,
+ aServiceIdValue);
+ }
+ }
+
+ /** class for mapping service entry to required objectclass,
+ RDN and attribute */
+ public static class ServiceMapping {
+ String mEntryRDN = null;
+ LDAPAttributeSet mAttrSet = new LDAPAttributeSet();
+
+ ServiceMapping(String aObjectClass, String aEntryRDN) {
+ mAttrSet.add(new LDAPAttribute(LDAP_OBJCLASS, aObjectClass));
+ mEntryRDN = aEntryRDN;
+ }
+
+ ServiceMapping(String aObjectClass, String aServiceIdValue,
+ String aEntryRDN) {
+ mAttrSet.add(new LDAPAttribute(LDAP_OBJCLASS, aObjectClass));
+ mAttrSet.add(new LDAPAttribute(SUNSERVICEID_ATTR, aServiceIdValue));
+ mEntryRDN = aEntryRDN;
+ }
+
+ public String getRDN() { return mEntryRDN; }
+ }
+
+ /**
+ * Static constructor, initialises the list of objectclasses and
+ * attriubtes for the service entry and the profile container,
+ * profile and policy entries.
+ */
+ static {
+ int i = 0;
+ // ou=ApocRegistry
+ SERVICE_MAPPING_ELEMENTS [i++] = new ServiceMapping(
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ SERVICE_REGISTRY,
+ CONFIG_NAMING_ATTR + SERVICE_REGISTRY);
+ // ou=default
+ SERVICE_MAPPING_ELEMENTS [i++] = new ServiceMapping(
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ CONFIG_NAMING_ATTR + SERVICE_DEFAULT);
+ // ou=OrganizationConfig
+ SERVICE_MAPPING_ELEMENTS [i++] = new ServiceMapping(
+ ORG_UNIT_OBJCLASS,
+ CONFIG_NAMING_ATTR + SERVICE_ORG_CONFIG);
+ // ou=1.0
+ SERVICE_MAPPING_ELEMENTS [i++] = new ServiceMapping(
+ SUNSERVICE_OBJCLASS,
+ CONFIG_NAMING_ATTR + SERVICE_VERSION);
+ // ou=ApocService
+ SERVICE_MAPPING_ELEMENTS [i++] = new ServiceMapping(
+ SUNSERVICE_OBJCLASS,
+ CONFIG_NAMING_ATTR + SERVICE_APOC);
+ // ou=Services
+ SERVICE_MAPPING_ELEMENTS [i++] = new ServiceMapping(
+ ORG_UNIT_OBJCLASS,
+ CONFIG_NAMING_ATTR + SERVICES);
+ CONTAINER_MAPPING = new EntryMapping(SUNSERVICE_COMPONENT_OBJCLASS,
+ "ApocPolicyGroupContainer");
+ PROFILE_MAPPING = new EntryMapping(SUNSERVICE_COMPONENT_OBJCLASS,
+ SUNSERVICEID_PROFILE);
+ POLICY_MAPPING = new EntryMapping(SUNSERVICE_COMPONENT_OBJCLASS,
+ SUNSERVICEID_POLICY);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param aBaseEntry base entry in the LDAP datasource
+ * @param aContext client context
+ * @throws <code>SPIException</code>
+ */
+ public LdapDataStore(String aBaseEntry,
+ LdapClientContext aContext)
+ throws SPIException {
+ readBootstrapData(aBaseEntry);
+ }
+
+ public void setVersion(MetaConfiguration metaConfData) {
+ // get version from MetaConfiguration, default is 1.0
+ String version = metaConfData.getString(VERSION_KEY);
+ if (version != null) {
+ try {
+ versionNb = Float.parseFloat(version);
+ isVersion1 = versionNb < 2.0f;
+ } catch (NumberFormatException ignored) {}
+ }
+ }
+
+ /**
+ * returns if the MetaConfiguration comes from APOC 1
+ * @return true if MetaConfiguration comes from APOC 1
+ */
+ public boolean isVersion1() { return isVersion1; }
+
+ /**
+ * Accessor for Base Distinguished Name.
+ *
+ * @return base DN
+ */
+ public String getBaseDN() { return mBaseDN; }
+
+ /**
+ * Accessor for Root Service Entry DN.
+ *
+ * @return DN for Root Service Entry
+ */
+ public String getRootServiceEntryDN() {
+ return mRootServiceEntryDNBuf.toString();
+ }
+
+ /**
+ * Accessor for Services Entry DN.
+ *
+ * @return DN for Services Entry
+ */
+ public String getServiceEntryDN() {
+ return mServiceEntryDNBuf.toString();
+ }
+
+ /**
+ * Extracts LDAP settings from bootstrapping source.
+ *
+ * @param aBaseDN DN for base entry
+ */
+ private void readBootstrapData(String aBaseDN) {
+ mBaseDN = aBaseDN;
+ mServiceEntryDNBuf = new StringBuffer(BUFFER_LENGTH) ;
+ for (int i = 0 ; i < NUMBER_OF_SERVICE_MAPPING_ELEMENTS ; ++ i) {
+ mServiceEntryDNBuf.append(SERVICE_MAPPING_ELEMENTS[i].mEntryRDN);
+ if (i + 1 < NUMBER_OF_SERVICE_MAPPING_ELEMENTS) {
+ mServiceEntryDNBuf.append(LdapEntity.LDAP_SEPARATOR) ;
+ }
+ }
+ mRootServiceEntryDNBuf.append(mServiceEntryDNBuf).append(
+ LdapEntity.LDAP_SEPARATOR).append(mBaseDN);
+ }
+
+ /**
+ * Returns a <code>Vector</code> listing the members of the specified type for
+ * a role. The members returned are those within the same organizational subtree
+ * as the role, and include any specified required attribute values.
+ * If no such members are found then an empty <code>Vector</code> is returned.
+ *
+ * @param aRoleEntity role whose members are required
+ * @param aObjectClass object class for member
+ * @param aMemberAttribute attribute used by member to store role membership
+ * @param aAttributes member attributes required
+ * @param aTypeOfSearch if <code>true</code> then just checks if
+ * there are children of this type, otherwise
+ * returns the children
+ * @param aReturnValue if just checking if there are children then
+ * this will indicate if there are childen,
+ * <code>true</code>, or if there are none,
+ * <code>false</code>
+ * @return <code>Vector</code> detailing the members
+ * @throws <code>SPIException</code> if an error occurs
+ */
+ public Vector getRoleMembers(LdapRole aRole, String aObjectClass,
+ String aMemberAttribute,
+ String[] aAttributes,
+ boolean aTypeOfSearch,
+ BooleanReturnValue aReturnValue)
+ throws SPIException {
+ StringBuffer searchBuf = new StringBuffer(BUFFER_LENGTH);
+ searchBuf.append("(&(");
+ searchBuf.append(LDAP_OBJCLASS);
+ searchBuf.append("=");
+ searchBuf.append(aObjectClass);
+ searchBuf.append(")(");
+ searchBuf.append(aMemberAttribute);
+ searchBuf.append("=");
+ searchBuf.append(aRole.getLocation());
+ searchBuf.append("))");
+ Vector returnList = null;
+ returnList = performSearch(
+ ((LdapNode)aRole.getParentOrgOrDomain())
+ .getLocation(),
+ RECURSIVE_SEARCH,
+ searchBuf.toString(),
+ aAttributes,
+ true,
+ aTypeOfSearch,
+ aReturnValue,
+ false,
+ aRole.getContext());
+ return returnList == null ? new Vector(): returnList;
+ }
+
+
+ /**
+ * Utility function that searchs the datastore for a list
+ * of children of a particular type for the specified entity.
+ *
+ * @param aParentEntity parent container
+ * @param aContainer container for children
+ * @param aClassFilter filter for search
+ * @param aIsRecursive <code>true</code> if require all children,
+ * <code>false</code> if only want children at
+ * this depth
+ * @param aAttributes child attributes required
+ * @param aTypeOfSearch if <code>true</code> then just checks if
+ * there are children of this type, otherwise
+ * returns the children
+ * @param aContext client context
+ * @param aReturnValue if just checking if there are children then
+ * this will indicate if there are childen,
+ * <code>true</code>, or if there are none,
+ * <code>false</code>
+ * @return list of DNs for the children found
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public Vector getListOfChildren(
+ LdapNode aParentEntity,
+ String aContainer, String aClassFilter, boolean aIsRecursive,
+ String[] aAttributes, boolean aTypeOfSearch,
+ LdapClientContext aContext, BooleanReturnValue aReturnValue)
+ throws SPIException {
+ StringBuffer startBuf = new StringBuffer(BUFFER_LENGTH);
+ if (aContainer != null) {
+ startBuf.append(aContainer).append(LdapEntity.LDAP_SEPARATOR);
+ }
+ startBuf.append(aParentEntity.getLocation());
+ Vector returnList = performSearch(
+ startBuf.toString(), aIsRecursive,
+ aClassFilter, aAttributes, true,
+ aTypeOfSearch, aReturnValue, false,
+ aContext);
+ return returnList;
+ }
+
+
+ /**
+ * Reads the contents of a list of attributes and returns the
+ * resulting <code>LDAPEntry</code>.
+ *
+ * @param aDN Distinguished Name for this read
+ * @param aAttributes attributes to be read
+ * @param aContext client context
+ * @return a table of attribute/value pairs
+ * @throws <code>LDAPException</code> if LDAP
+ * error occurs
+ */
+ private LDAPEntry readAttributes(String aDN, String aAttributes [],
+ LdapClientContext aContext)
+ throws LDAPException {
+ LDAPConnection connection = aContext.getConnection() ;
+ LDAPEntry entry = connection.read(aDN, aAttributes);
+ return entry;
+ }
+
+ /**
+ * Reads all attributes in an entry plus its timestamp and puts one
+ * value for each in a hashtable of attribute name to byte array value.
+ */
+ public Hashtable readAllAttributes(String aDn,
+ LdapClientContext aContext) throws LDAPException {
+ String [] allAttributes = { "*", MODIFY_TIMESTAMP_ATTR } ;
+ LDAPEntry entry = aContext.getConnection().read(aDn, allAttributes) ;
+ Enumeration attributes = entry.getAttributeSet().getAttributes() ;
+ Hashtable retCode = new Hashtable() ;
+
+ while (attributes.hasMoreElements()) {
+ LDAPAttribute attribute =
+ (LDAPAttribute) attributes.nextElement() ;
+ Enumeration values = attribute.getByteValues() ;
+
+ if (values.hasMoreElements()) {
+ retCode.put(attribute.getName(), values.nextElement()) ;
+ }
+ }
+ return retCode ;
+ }
+
+ /**
+ * Reads an entry and returns the DN. Used when want to find
+ * the display name for an <code>Entity</code>.
+ *
+ * @param aDN distinguished name derived from
+ * <code>Entity</code>
+ * @param aContext client context
+ * @return distinguished name as read from LDAP
+ * @throws IllegalReadException if LDAP error occurs
+ */
+ public String readEntryDN(String aDN, LdapClientContext aContext)
+ throws SPIException {
+ String dn = null;
+ // Need to lookup just one attribute explicitly, otherwise all the
+ // entry's contents are transmitted over the network, at least for
+ // OpenLDAP implementations.
+ String [] noAttributes = { "objectclass" } ;
+
+ try {
+ LDAPConnection connection = aContext.getConnection();
+ LDAPEntry entry = connection.read(aDN, noAttributes);
+ if (entry != null) {
+ dn = entry.getDN();
+ }
+ } catch (LDAPException ldape) {
+ if (ldape.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
+ throw new NoSuchEntityException(aDN);
+ } else {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ }
+ return dn;
+ }
+
+
+
+ /**
+ * Reads the contents of an array of attributes and puts the
+ * attribute/value(s) mappings in a Hashtable.
+ *
+ * @param aDN Distinguished name for this layer
+ * @param aDNRequired <code>true</code> if DN required,
+ * otherwise <code>false</code>
+ * @param aAttributes array of attribute names to be read
+ * @param aContext client context
+ * @return table containing the attribute/value(s) mappings
+ * @throws <code>LDAPException</code> if LDAP
+ * error occurs
+ */
+ public Hashtable getAttributeValueTable(String aDN, boolean aDNRequired,
+ String aAttributes [], LdapClientContext aContext)
+ throws LDAPException {
+ LDAPEntry entry = null;
+ entry = readAttributes(aDN, aAttributes, aContext);
+ Hashtable retTable = new Hashtable();
+ if (entry != null) {
+ if (aDNRequired) {
+ Vector values = new Vector();
+ values.add(entry.getDN());
+ retTable.put(DN_KEY, values);
+ }
+ for (int i = 0 ; i < aAttributes.length ; ++ i) {
+ retTable.put(aAttributes[i],
+ getAllValues(entry, aAttributes[i]));
+ }
+ }
+ return retTable ;
+ }
+
+ /**
+ * Reads the contents of an array of attributes and returns the
+ * value in a <code>Vector</code>.
+ *
+ * @param aDN Distinguished Name of layer to be accessed
+ * @param aAttributes array of attributes to be read
+ * @param aTypeOfSearch if <code>true</code> then just checks if
+ * values exist, otherwise processes values
+ * @param aIncludeDN if <code>true</code> then add read DN of
+ * entry to end of returned list, otherwise don't
+ * @param aContext client context
+ * @param aReturnValue if just checking if there are values then
+ * this will indicate if there are,
+ * <code>true</code>, or if there are none,
+ * <code>false</code>
+ * @return <code>Vector</code> containing the attribute
+ * values
+ * @throws <code>LDAPException</code> if LDAP
+ * error occurs
+ */
+ public Vector getAttributeValueList(String aDN, String[] aAttributes,
+ boolean aTypeOfSearch,
+ boolean aIncludeDN,
+ LdapClientContext aContext,
+ BooleanReturnValue aReturnValue)
+ throws LDAPException {
+ Vector entityList = new Vector();
+ LDAPEntry entry = null;
+ entry = readAttributes(aDN, aAttributes, aContext);
+ if (entry != null) {
+ for (int i = 0 ; i < aAttributes.length ; ++ i) {
+ LDAPAttribute attribute=entry.getAttribute(aAttributes[i]);
+ if (attribute != null) {
+ /* If just checking that values exist, then
+ return here */
+ if(aTypeOfSearch) {
+ aReturnValue.setReturnValue(true);
+ return entityList;
+ }
+ Enumeration enumVal = attribute.getStringValues();
+ while (enumVal.hasMoreElements()) {
+ entityList.add((String)enumVal.nextElement());
+ }
+ }
+ }
+ if (aIncludeDN) {
+ entityList.add(entry.getDN());
+ }
+ }
+ return entityList ;
+ }
+ /**
+ * Reads the contents of an array of attributes and returns the
+ * value in a <code>Vector</code>.
+ *
+ * @param aDN Distinguished Name of layer to be accessed
+ * @param aAttributes array of attributes to be read
+ * @param aContext client context
+ * @return <code>Vector</code> containing the attribute
+ * values
+ * @throws <code>LDAPException</code> if
+ * error occurs
+ */
+ public Vector getAttributeValueList(String aDN, String[] aAttributes,
+ LdapClientContext aContext)
+ throws LDAPException {
+ return getAttributeValueList(aDN, aAttributes, false, false, aContext,
+ new BooleanReturnValue(false));
+ }
+
+ /**
+ * Carries out an LDAP search and returns the results
+ * in a <code>Vector</code>.
+ *
+ * @param aRelativeDn RelativeDN of place in Directory Tree
+ * to start search
+ * @param aRecursiveSearch <code>boolean</code> value indicating whether
+ * to carry out a search recursively,
+ * <code>true</code>, or to one level only,
+ * <code>false</code>
+ * @param aSearchFilter filter (search criteria) for the LDAP search
+ * @param aAttributes attributes to search for
+ * @param aDNRequired <code>true</code> if DNs required,
+ * otherwise <code>false</code>
+ * @param aCheckOnly <code>boolean</code> indicating if only
+ * checking if entries found, <code>true</code>,
+ * or not, <code>false</code>
+ * @param aSuccess only used if aCheckOnly is <code>true</code>.
+ * indicates if entries found from search
+ * <code>true</code>, or not, <code>false</code>
+ * @param aAttributesOnly <code>boolean</code> indicating if only
+ * attributes should be retrieved,
+ * <code>true</code>, or whether attributes and
+ * values should be retrieved, <code>false</code>.
+ * @param aContext client context
+ * @return <code>Vector</code> containing a Hashtable
+ * of the attribute values for each entry
+ * @throws IllegalReadException if
+ * LDAP error occurs
+ */
+ public Vector performSearch (String aRelativeDn,
+ boolean aRecursiveSearch,
+ String aSearchFilter,
+ String[] aAttributes,
+ boolean aDNRequired,
+ boolean aCheckOnly,
+ BooleanReturnValue aReturnValue,
+ boolean aAttributesOnly,
+ LdapClientContext aContext)
+ throws IllegalReadException {
+ return performSearch(aRelativeDn, aRecursiveSearch,
+ aSearchFilter, aAttributes,
+ aDNRequired, aCheckOnly,
+ aReturnValue, aAttributesOnly,
+ aContext.getConnection());
+ }
+
+ /**
+ * Carries out an LDAP search and returns the results
+ * in a <code>Vector</code>.
+ *
+ * @param aRelativeDn RelativeDN of place in Directory Tree
+ * to start search
+ * @param aRecursiveSearch <code>boolean</code> value indicating whether
+ * to carry out a search recursively,
+ * <code>true</code>, or to one level only,
+ * <code>false</code>
+ * @param aSearchFilter filter (search criteria) for the LDAP search
+ * @param aAttributes attributes to search for
+ * @param aDNRequired <code>true</code> if DNs required,
+ * otherwise <code>false</code>
+ * @param aCheckOnly <code>boolean</code> indicating if only
+ * checking if entries found, <code>true</code>,
+ * or not, <code>false</code>
+ * @param aSuccess only used if aCheckOnly is <code>true</code>.
+ * indicates if entries found from search
+ * <code>true</code>, or not, <code>false</code>
+ * @param aAttributesOnly <code>boolean</code> indicating if only
+ * attributes should be retrieved,
+ * <code>true</code>, or whether attributes and
+ * values should be retrieved, <code>false</code>.
+ * @param aConnection client connection
+ * @return <code>Vector</code> containing a Hashtable
+ * of the attribute values for each entry
+ * @throws IllegalReadException if
+ * LDAP error occurs
+ */
+ public Vector performSearch (String aRelativeDn,
+ boolean aRecursiveSearch,
+ String aSearchFilter,
+ String[] aAttributes,
+ boolean aDNRequired,
+ boolean aCheckOnly,
+ BooleanReturnValue aReturnValue,
+ boolean aAttributesOnly,
+ LDAPConnection aConnection)
+ throws IllegalReadException {
+ Vector entityList = new Vector();
+ LDAPSearchResults results = null;
+ try {
+ results = doSearch(aRelativeDn,
+ aRecursiveSearch,
+ aSearchFilter,
+ aAttributes,
+ aAttributesOnly,
+ aConnection);
+ if (aCheckOnly) {
+ if(results.hasMoreElements()) {
+ aReturnValue.setReturnValue(true);
+ }
+ aConnection.abandon(results) ;
+ return entityList;
+ }
+ while (results.hasMoreElements()) {
+ Hashtable attrsValues = new Hashtable();
+ LDAPEntry entry = results.next();
+ if (aDNRequired) {
+ Vector dnValues = new Vector();
+ dnValues.add(entry.getDN());
+ attrsValues.put(DN_KEY, dnValues);
+ }
+ if (aAttributes != null) {
+ for (int i = 0; i < aAttributes.length; ++i) {
+ attrsValues.put(aAttributes[i],
+ getAllValues(entry, aAttributes[i]));
+ }
+ }
+ entityList.add(attrsValues);
+ }
+ } catch (LDAPException ldape) {
+ int result = ldape.getLDAPResultCode();
+ if (result == LDAPException.ADMIN_LIMIT_EXCEEDED) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_SIZE_READ_KEY, ldape);
+ }
+ else if (result != LDAPException.SIZE_LIMIT_EXCEEDED){
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ }
+ return entityList;
+ }
+
+ /**
+ * Performs an LDAP search and returns the DN and attribute
+ * values for each entry found. The results are returned as
+ * a <code>Vector</code> of <code>Vector</code>s, each element
+ * containing all the values for the attributes.
+ * In case the DN was asked in addition of the attributes,
+ * its value is stored in the last slot of the returned element.
+ *
+ * @param aBaseDn base DN of the search
+ * @param aRecursive is the search recursive?
+ * @param aFilter search filter
+ * @param aAttributes attribute list
+ * @param aRetrieveDn do we also want the DNs?
+ * @param aContext context to the repository
+ * @return <code>Vector</code> containing value arrays
+ * for each entry found
+ * @throws IllegalReadException if an error occurs.
+ */
+ public Vector getEntriesAttributes (String aBaseDn,
+ boolean aRecursive,
+ String aFilter,
+ String [] aAttributes,
+ boolean aRetrieveDn,
+ LdapClientContext aContext)
+ throws SPIException {
+ Vector retCode = new Vector() ;
+ try {
+ LDAPSearchResults results =
+ doSearch(aBaseDn, aRecursive, aFilter, aAttributes,
+ false, aContext);
+
+ while (results.hasMoreElements()) {
+ LDAPEntry entry = results.next() ;
+ Vector allEntryAttrValues = new Vector();
+ for (int i = 0; i < aAttributes.length; ++i) {
+ Vector values = getAllValues(entry, aAttributes[i]);
+ if (values != null && !values.isEmpty()) {
+ for (int j = 0; j < values.size(); ++j) {
+ allEntryAttrValues.add((String)values.get(j));
+ }
+ }
+ }
+ if (aRetrieveDn) { allEntryAttrValues.add(entry.getDN());}
+ retCode.add(allEntryAttrValues) ;
+ }
+ }
+ catch (LDAPException ldape) {
+ int result = ldape.getLDAPResultCode() ;
+ if ( (result == LDAPException.SIZE_LIMIT_EXCEEDED)
+ || (result == LDAPException.ADMIN_LIMIT_EXCEEDED)) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_SIZE_READ_KEY, ldape);
+ }
+ else {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ }
+ return retCode ;
+ }
+
+ /**
+ * Carries out an LDAP search and returns the
+ * <code>LDAPSearchResults</code>
+ *
+ * @param aRelativeDn RelativeDN of place in Directory Tree
+ * to start search
+ * @param aRecursiveSearch <code>boolean</code> value indicating whether
+ * to carry out a search recursively,
+ * <code>true</code>, or to one level only,
+ * <code>false</code>
+ * @param aSearchFilter filter (search criteria) for the LDAP search
+ * @param aAttributes attributes to search for
+ * @param aAttributesOnly <code>boolean</code> indicating if only
+ * attributes should be retrieved,
+ * <code>true</code>, or whether attributes and
+ * values should be retrieved, <code>false</code>
+ * @param aContext client context
+ * @return <code>LDAPSearchResults</code>
+ * @throws <code>LDAPException</code> if LDAP error occurs
+ */
+ private LDAPSearchResults doSearch (String aRelativeDn,
+ boolean aRecursiveSearch,
+ String aSearchFilter,
+ String[] aAttributes,
+ boolean aAttributesOnly,
+ LdapClientContext aContext)
+ throws LDAPException {
+ return doSearch(aRelativeDn, aRecursiveSearch, aSearchFilter,
+ aAttributes, aAttributesOnly,
+ aContext.getConnection());
+ }
+
+ /**
+ * Carries out an LDAP search and returns the
+ * <code>LDAPSearchResults</code>
+ *
+ * @param aRelativeDn RelativeDN of place in Directory Tree
+ * to start search
+ * @param aRecursiveSearch <code>boolean</code> value indicating whether
+ * to carry out a search recursively,
+ * <code>true</code>, or to one level only,
+ * <code>false</code>
+ * @param aSearchFilter filter (search criteria) for the LDAP search
+ * @param aAttributes attributes to search for
+ * @param aAttributesOnly <code>boolean</code> indicating if only
+ * attributes should be retrieved,
+ * <code>true</code>, or whether attributes and
+ * values should be retrieved, <code>false</code>
+ * @param aConnection client LDAP connection
+ * @return <code>LDAPSearchResults</code>
+ * @throws <code>LDAPException</code> if LDAP error occurs
+ */
+ private LDAPSearchResults doSearch (String aRelativeDn,
+ boolean aRecursiveSearch,
+ String aSearchFilter,
+ String[] aAttributes,
+ boolean aAttributesOnly,
+ LDAPConnection aConnection)
+ throws LDAPException {
+ /* Perform a search for entries at one level below
+ the relativeDn by default */
+ int scope = LDAPv2.SCOPE_ONE;
+
+ if (aRecursiveSearch) {
+ scope = LDAPv2.SCOPE_SUB;
+ }
+ if (aRelativeDn == null) { aRelativeDn = mBaseDN ; }
+ return aConnection.search( aRelativeDn,
+ scope,
+ aSearchFilter,
+ aAttributes,
+ aAttributesOnly);
+ }
+
+ /**
+ * Deletes an entry from the LDAP datastore.
+ * @param aDN entry DN
+ * @param aContext client context
+ *
+ * @throws <code>LDAPException</code> if entry cannot be
+ * deleted
+ */
+ private void deleteEntry(String aDN, LdapClientContext aContext)
+ throws LDAPException {
+ aContext.getConnection().delete(aDN);
+ }
+
+ /**
+ * Renames an entry in the LDAP datastore.
+ * @param aDN entry DN
+ * @param aNewRDN new RDN
+ * @param aContext client context
+ *
+ * @throws <code>LDAPException</code> if entry cannot be
+ * deleted
+ */
+ private void renameEntry(String aDN, String aRDN,
+ LdapClientContext aContext)
+ throws LDAPException {
+ aContext.getConnection().rename(aDN, aRDN, true);
+ }
+
+ /**
+ * Creates an LDAP entry.
+ *
+ * @param aDN DN for this new entry
+ * @param aAttrs set of attributes to be added to the
+ * entry
+ * @param aConnection client LDAP connection
+ * @throws <code>LDAPException</code> if error occurs
+ */
+ private void addEntry(String aDN, LDAPAttributeSet aAttrs,
+ LDAPConnection aConnection)
+ throws LDAPException{
+ /* create the entry to be added */
+ String [] dn = LDAPDN.explodeDN(aDN, false) ;
+ int equalSign = dn [0].indexOf('=') ;
+ String attr = dn [0].substring(0, equalSign) ;
+
+ if (aAttrs.getAttribute(attr) == null) {
+ aAttrs.add(new LDAPAttribute(attr,
+ dn [0].substring(equalSign + 1)));
+ }
+ LDAPEntry newEntry = new LDAPEntry(aDN, aAttrs);
+ aConnection.add(newEntry);
+ }
+
+
+ /**
+ * Writes a list of changes to the repository.
+ *
+ * @param aDN DN of the entity to be modified
+ * @param aContainer name of the container
+ * @param aChanges array of <code>Change</code> containing
+ * the new attribute/value pairs
+ * @param aIsMultiValued <code>true</code> if attribute is multivalued,
+ * otherwise <code>false</code>
+ * @param aConnection client connection
+ * @throws IllegalWriteException if LDAP error occurs
+ */
+ private void writeAttributes(String aDN, String aContainer,
+ Change[] aChanges, boolean aIsMultiValued,
+ LDAPConnection aConnection)
+ throws SPIException {
+ LDAPModificationSet set = new LDAPModificationSet() ;
+ try {
+ if (!containsContainer(aDN, aContainer, aConnection)) {
+ set.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_OBJCLASS, aContainer));
+ }
+ LDAPAttribute attribute;
+ for (int i = 0 ; i < aChanges.length ; ++ i) {
+ if (aIsMultiValued) {
+ attribute = new LDAPAttribute(aChanges[i].mName,
+ aChanges[i].mValues) ;
+ } else {
+ attribute = new LDAPAttribute(aChanges[i].mName,
+ aChanges[i].mValues[0]) ;
+ }
+ set.add(LDAPModification.REPLACE, attribute);
+ }
+ aConnection.modify(aDN, set) ;
+ }
+ catch (LDAPException ldape) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY, ldape);
+ }
+ }
+
+ /**
+ * Deletes a list of attribute values from an entity.
+ *
+ * @param aDN DN of the entity to be modified
+ * @param aContainer name of the container
+ * @param aChanges array of <code>Change</code> containing
+ * the attribute/value pairs
+ * @param aIsMultiValued <code>true</code> if attribute is multivalued,
+ * otherwise <code>false</code>
+ * @param aConnection client connection
+ * @throws IllegalReadException if LDAP error occurs
+ */
+ private void deleteAttributeValues(String aDN, String aContainer,
+ Change [] aChanges,
+ boolean aIsMultiValued,
+ LDAPConnection aConnection)
+ throws SPIException {
+ LDAPModificationSet set = new LDAPModificationSet() ;
+ try {
+ LDAPAttribute attribute;
+ for (int i = 0 ; i < aChanges.length ; ++ i) {
+ if (aIsMultiValued) {
+ attribute = new LDAPAttribute(aChanges[i].mName,
+ aChanges[i].mValues) ;
+ } else {
+ attribute = new LDAPAttribute(aChanges[i].mName,
+ aChanges[i].mValues[0]) ;
+ }
+ set.add(LDAPModification.DELETE, attribute);
+ }
+ aConnection.modify(aDN, set) ;
+ }
+ catch (LDAPException ldape) {
+ int error = ldape.getLDAPResultCode();
+ if ( (error != LDAPException.NO_SUCH_ATTRIBUTE)
+ && (error != LDAPException.NO_SUCH_OBJECT) ) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ }
+ }
+
+ /**
+ * Checks if an entry exists in the repository.
+ *
+ * @param aDN DN for entry
+ * @param aContext client context
+ * @return <code>true</code> if entry exists, otherwise
+ * <code>false</code>
+ * @throws LDAPException
+ */
+ public boolean entryExists(String aDN, LdapClientContext aContext)
+ throws LDAPException {
+ return entryExists(aDN, aContext.getConnection());
+ }
+
+ private boolean entryExists(String aDn, LDAPConnection aConnection)
+ throws LDAPException{
+ try {
+ aConnection.read(aDn) ;
+ return true ;
+ }
+ catch (LDAPException ldape) {
+ int error = ldape.getLDAPResultCode();
+ if ( (error != LDAPException.NO_SUCH_ATTRIBUTE)
+ && (error != LDAPException.NO_SUCH_OBJECT) ) {
+ throw ldape;
+ }
+ }
+ return false ;
+ }
+
+ /**
+ * Queries whether a particular object class is present in an entry.
+ *
+ * @param aDN DN for this entity
+ * @param aContainer object class to force
+ * @param aConnection client connection
+ * @return true if the object class is present in the entry
+ */
+ private boolean containsContainer(String aDN, String aObjectClass,
+ LDAPConnection aConnection)
+ throws LDAPException {
+ String [] attributes = new String [1] ;
+ attributes [0] = LDAP_OBJCLASS ;
+ LDAPEntry entry = aConnection.read(aDN, attributes) ;
+ if (entry != null) {
+ LDAPAttribute attribute = entry.getAttribute(attributes [0]) ;
+ if (attribute != null) {
+ Enumeration values = attribute.getStringValues() ;
+ while (values.hasMoreElements()) {
+ if (aObjectClass.equalsIgnoreCase(
+ (String) values.nextElement())) {
+ return true ;
+ }
+ }
+ }
+ }
+ return false ;
+ }
+
+ /**
+ * Deletes values from a multi-valued attribute for a specific entity id.
+ *
+ * @param aDN entity to be modified
+ * @param aAttributes attribute
+ * @param aValues value list
+ * @param aContainer object class allowing this attribute
+ * @param aContext context to the repository
+ * @throws SPIException if an error occurs
+ */
+ public void removeMultiValuedAttributeValues(String aDN,
+ String aAttribute,
+ String [] aValues,
+ String aContainer,
+ LdapClientContext aContext)
+ throws SPIException {
+ if (aAttribute == null || aValues == null) {
+ throw new IllegalArgumentException();
+ }
+ Change [] changes = new Change [1] ;
+ changes [0] = new Change(aAttribute, aValues) ;
+ LDAPConnection connection;
+ connection = aContext.getConnection() ;
+ deleteAttributeValues(aDN, aContainer, changes, true, connection);
+ }
+
+
+ /**
+ * Writes values for a single-valued attribute to a specific entity id.
+ *
+ * @param aDN entity to be modified
+ * @param aAttributes attribute list
+ * @param aValues value list aligned on attribute one
+ * @param aContainer object class allowing these attributes
+ * @param aContext context to the repository
+ * @throws SPIException if an error occurs
+ */
+ public void fillAttributes(String aDN,
+ String [] aAttributes,
+ String [] aValues,
+ String aContainer,
+ LdapClientContext aContext)
+ throws SPIException {
+ if (aAttributes == null || aValues == null ||
+ aAttributes.length != aValues.length) {
+ throw new IllegalArgumentException();
+ }
+ int numOfAttributes = aAttributes.length;
+ Change [] changes = new Change [numOfAttributes] ;
+ for (int i = 0 ; i < numOfAttributes ; ++ i) {
+ changes [i] = new Change(aAttributes [i], aValues[i]) ;
+ }
+ LDAPConnection connection;
+ connection = aContext.getConnection() ;
+ writeAttributes(aDN, aContainer, changes, false, connection) ;
+ }
+
+ /**
+ * Adds values for a multi-valued attribute to a specific entity.
+ *
+ * @param aDN entry to be modified
+ * @param aAttribute multi-valued attribute name
+ * @param aValues multi-valued list
+ * @param aContainer object class allowing this attribute
+ * @param aContext context to the repository
+ * @throws IllegalReadException if LDAP error occurs
+ * @throws SPIException if an error occurs
+ */
+ public void addValuesToMultiValuedAttribute(String aDN,
+ String aAttribute,
+ String [] aValues,
+ String aContainer,
+ LdapClientContext aContext)
+ throws SPIException {
+ if (aAttribute == null || aValues == null) {
+ throw new IllegalArgumentException();
+ }
+ Vector entityList = new Vector();
+ LDAPConnection connection = null;
+ HashSet uniqueValues = new HashSet();
+ LDAPEntry entry = null;
+ try {
+ connection = aContext.getConnection() ;
+ entry = connection.read(aDN);
+ } catch (LDAPException ldape1) {
+ if (ldape1.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
+ try {
+ String shortDN = getDNExcludingServiceEntry(aDN);
+ ensureServiceEntryExistsForEntry(shortDN, connection);
+ entry = connection.read(aDN);
+ } catch (LDAPException ldape2) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape2);
+ }
+ } else {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape1);
+ }
+ }
+ LDAPAttribute attribute = entry.getAttribute(aAttribute);
+ if (attribute != null) {
+ Enumeration enumVals = attribute.getStringValues();
+ while (enumVals.hasMoreElements()) {
+ uniqueValues.add(((String)enumVals.nextElement()));
+ }
+ }
+ for (int i = 0; i < aValues.length; ++i) {
+ uniqueValues.add(aValues[i]);
+ }
+ Change [] changes = new Change [1] ;
+ changes[0] = new Change();
+ changes[0].mName = aAttribute;
+ int size = uniqueValues.size();
+ changes[0].mValues = new String[size];
+ Iterator values = uniqueValues.iterator();
+ int index = 0;
+ while (values.hasNext()){
+ changes[0].mValues[index ++] = (String)values.next();
+ }
+ writeAttributes(aDN, aContainer, changes, true, connection);
+ }
+
+ /**
+ * Builds the XML-Blob(tm) representing the component data
+ * given the LDAP attributes of the entity.
+ *
+ * @param aValues the table of attribute/value keys
+ * @param aAttributes the attribute names which act as keys to the
+ * table
+ * @return string representing the contents of the component
+ * as an XML-Blob(tm)
+ */
+ String buildComponent(Hashtable aValues, String[] aAttributes) {
+ return (String) aValues.get(aAttributes[0]) ;
+ }
+
+ /**
+ * Utility class representing an attribute/value
+ * pair to be used in a change operation.
+ */
+ public static class Change
+ {
+ /** Attribute name */
+ String mName ;
+ /** Attribute values */
+ String []mValues ;
+
+ public Change() {}
+
+ public Change(String aName, String []aValues) {
+ mName = aName ; mValues = aValues ;
+ }
+ public Change(String aName, String aValue) {
+ mName = aName;
+ mValues = new String[1];
+ mValues[0] = aValue ;
+ }
+ }
+
+
+ /**
+ * Utility function to build the filter corresponding to a list
+ * of components for a search, i.e either an overall filter,
+ * a single value one or an OR between the possible values.
+ *
+ * @param aPolicyIds array of component names
+ * @param aIdParser used to build stored component names
+ * @return filter
+ */
+ private static String buildComponentNameFilter(
+ String [] aPolicyIds,
+ PolicyIdParser aIdParser) {
+ StringBuffer retCode = new StringBuffer("(") ;
+
+ if (aPolicyIds.length > 1) {
+ retCode.append("|") ;
+ for (int i = 0 ; i < aPolicyIds.length ; ++ i) {
+ retCode.append("(").append(CONFIG_NAMING_ATTR) ;
+ retCode.append(aIdParser.getStoredFormat(aPolicyIds [i])) ;
+ retCode.append(")") ;
+ }
+ }
+ else {
+ retCode.append(CONFIG_NAMING_ATTR) ;
+ if (aPolicyIds.length == 0) {
+ retCode.append(LDAP_WILDCARD) ;
+ }
+ else {
+ retCode.append(aIdParser.getStoredFormat(aPolicyIds [0])) ;
+ }
+ }
+ retCode.append(")") ;
+ return retCode.toString() ;
+ }
+
+ /**
+ * Utility function to return the first value of a given attribute
+ * in an LDAP entry.
+ *
+ * @param aEntry LDAP entry
+ * @param aAttribute attribute name
+ * @return the first attribute value or null if any problem arises.
+ */
+ private static String getFirstValue(LDAPEntry aEntry, String aAttribute) {
+ LDAPAttribute attribute = aEntry.getAttribute(aAttribute) ;
+
+ if (attribute != null) {
+ Enumeration values = attribute.getStringValues() ;
+
+ if (values.hasMoreElements()) {
+ return (String) values.nextElement() ;
+ }
+ }
+ return null ;
+ }
+
+ /**
+ * Utility function to return all value for a given attribute
+ * in an LDAP entry.
+ *
+ * @param aEntry LDAP entry
+ * @param aAttribute attribute name
+ * @return a <code>Vector</code> of attribute values
+ */
+ private static Vector getAllValues(LDAPEntry aEntry, String aAttribute) {
+ Vector retCode = new Vector();
+ LDAPAttribute attribute = aEntry.getAttribute(aAttribute) ;
+ if (attribute == null) { return retCode; }
+ Enumeration values = attribute.getStringValues() ;
+ while (values.hasMoreElements()) {
+ retCode.add((String) values.nextElement()) ;
+ }
+ return retCode ;
+ }
+
+ private static final String [] TIMEONLY_POLICY_ATTRS =
+ { ORG_UNIT_NAMING_ATTR,
+ MODIFY_TIMESTAMP_ATTR} ;
+ private static final String [] ALL_POLICY_ATTRS = { ORG_UNIT_NAMING_ATTR,
+ MODIFY_TIMESTAMP_ATTR,
+ KEYVALUE_ATTR } ;
+ private static final String [] ALL_PROFILE_ATTRS =
+ { ORG_UNIT_NAMING_ATTR,
+ PRIORITY_ATTR,
+ MODIFY_TIMESTAMP_ATTR,
+ MODIFY_AUTHOR_ATTR,
+ KEYVALUE_ATTR } ;
+ /**
+ * Takes a key/value string and a key as parameters, and returns
+ * the value.
+ *
+ * @param aKeyValue key/value string
+ * @param aKey key
+ * @return value for this key
+ */
+ public static String getValueForKey(String aKeyValue,
+ String aKey) {
+ if (aKeyValue == null) {
+ return null;
+ }
+ String keyValue = null;
+ if (aKeyValue.startsWith(aKey)) {
+ int begin = aKeyValue.indexOf("=");
+ if (begin > 0) {
+ keyValue = aKeyValue.substring(++begin);
+ }
+ }
+ return keyValue;
+ }
+
+ /**
+ * Takes a list of key/value strings, finds those of the required
+ * key and returns those values in an array. If no values are found
+ * then the returned array is empty.
+ *
+ * @param aKeyValues <code>Vector</code> of key/value strings
+ * @param aKey required key
+ * @return values for this key
+ */
+ public static String[] getValuesForKey(Vector aKeyValues,
+ String aKey) {
+ if (aKeyValues == null || (aKeyValues.size() == 0)) {
+ return new String[0];
+ }
+ Vector values = new Vector();
+ String keyValue = null;
+ for (int i = 0; i < aKeyValues.size(); ++i) {
+ keyValue = (String)aKeyValues.get(i);
+ keyValue = getValueForKey(keyValue, aKey);
+ if (keyValue != null) {
+ values.add(keyValue);
+ }
+ }
+ int size = values.size();
+ String []retCode = new String[size];
+ for (int i = 0; i < size; ++i) {
+ retCode[i] = (String)values.get(i);
+ }
+ return retCode;
+ }
+ private String getDNExcludingServiceEntry(String aDN) {
+ String [] dnComponents = LDAPDN.explodeDN(aDN, false);
+ int numOfComponents = dnComponents.length ;
+ String []tmpComponents =
+ new String[numOfComponents - NUMBER_OF_SERVICE_MAPPING_ELEMENTS];
+ int index = 0;
+ for (int i = NUMBER_OF_SERVICE_MAPPING_ELEMENTS; i < numOfComponents; i++) {
+ tmpComponents[index ++] = dnComponents[i];
+ }
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ tmpBuf.append(tmpComponents[0]);
+ for (int i = 1; i < tmpComponents.length; ++i) {
+ tmpBuf.append(LdapEntity.LDAP_SEPARATOR);
+ tmpBuf.append(tmpComponents[i]);
+ }
+ return tmpBuf.toString();
+ }
+
+ /**
+ * Utility function that adds missing service entry elements
+ * to entries in the datastore.
+ *
+ * @param aStartDN entry which requires service subentry
+ * @param aConnection LDAP connection
+ * @return DN for entry
+ * @throws <code>LDAPException</code> if error occurs
+ */
+ public String ensureServiceEntryExistsForEntry(
+ String aStartDN, LDAPConnection aConnection)
+ throws LDAPException {
+ StringBuffer currentDn = new StringBuffer(BUFFER_LENGTH) ;
+ boolean alreadyThere = false ;
+
+ currentDn.append(mServiceEntryDNBuf) ;
+ currentDn.append(LdapEntity.LDAP_SEPARATOR) ;
+ currentDn.append(aStartDN) ;
+ try {
+ aConnection.read(currentDn.toString()) ;
+ alreadyThere = true ;
+ }
+ catch (LDAPException exception) {
+ if (exception.getLDAPResultCode()
+ != LDAPException.NO_SUCH_OBJECT) {
+ throw exception ;
+ }
+ }
+ if (alreadyThere) { return currentDn.toString() ; }
+ currentDn.delete(0, currentDn.length()) ;
+ currentDn.append(aStartDN) ;
+ for (int i=NUMBER_OF_SERVICE_MAPPING_ELEMENTS-1; i>=0; --i) {
+ currentDn.insert(0, LdapEntity.LDAP_SEPARATOR) ;
+ currentDn.insert(0, SERVICE_MAPPING_ELEMENTS[i].mEntryRDN);
+ try {
+ addEntry(currentDn.toString(),
+ SERVICE_MAPPING_ELEMENTS[i].mAttrSet,
+ aConnection);
+ }
+ catch (LDAPException exception) {
+ if (exception.getLDAPResultCode() !=
+ LDAPException.ENTRY_ALREADY_EXISTS) {
+ throw exception ;
+ }
+ }
+ }
+ return currentDn.toString() ;
+ }
+
+
+
+ /**
+ * For a given host or user entity returns the list of roles of which this
+ * entity is a member. If the entity is not a member of a role then an
+ * empty <code>Vector</code> is returned.
+ *
+ * @param aEntity entity whose membership information is required
+ * @param aListingAttribute attribute used to store membership information
+ * @param aClientContext client context
+ * @return <code>Vector</code> listing role entries
+ * @throws IllegalReadException if LDAP error occurs
+ */
+ public Vector getListedRolesForEntity(LdapEntity aEntity,
+ String aListingAttribute, LdapClientContext aContext)
+ throws SPIException {
+ Vector entityList = null;
+ String []attributes = new String[1];
+ attributes[0] = aListingAttribute;
+ try {
+ entityList = getAttributeValueList(aEntity.getLocation(),
+ attributes, aContext);
+ } catch (LDAPException ldape) {
+ int error = ldape.getLDAPResultCode();
+ if ( (error != LDAPException.NO_RESULTS_RETURNED)
+ && (error != LDAPException.NO_SUCH_ATTRIBUTE)
+ && (error != LDAPException.NO_SUCH_OBJECT) ) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ }
+ return entityList == null ? new Vector(): entityList;
+ }
+
+ /**
+ * Creates and returns object representing root organization.
+ *
+ * @param aEntityMapping entity mapping object
+ * @param aAuthorizedContext authorized client context
+ * @param aContext client context
+ * @return object representing root organization
+ * @throws SPIException if error occurs
+ */
+ public Organization createRootOrganization(
+ LdapEntityMapping aEntityMapping,
+ LdapClientContext aAuthorizedContext,
+ LdapClientContext aContext)
+ throws SPIException {
+ if (mRootDN == null) {
+ mRootDN = readEntryDN(getBaseDN(), aAuthorizedContext);
+ }
+ mRootOrganization = new LdapOrganization(mRootDN, -1, this,
+ aEntityMapping, aContext) ;
+ return mRootOrganization;
+ }
+
+ /**
+ * Returns object representing root organization.
+ *
+ * @return object representing root organization
+ */
+ public Organization getRootOrganization() { return mRootOrganization; }
+
+ /**
+ * Creates and returns object representing root domain.
+ *
+ * @param aEntityMapping entity mapping object
+ * @param aAuthorizedContext authorized client context
+ * @param aContext client context
+ * @return object representing root domain
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Domain createRootDomain(LdapEntityMapping aEntityMapping,
+ LdapClientContext aAuthorizedContext,
+ LdapClientContext aContext)
+ throws SPIException {
+ if (mRootDN == null) {
+ mRootDN = readEntryDN(getBaseDN(), aAuthorizedContext);
+ }
+ mRootDomain = new LdapDomain(
+ LdapEntity.DOMAIN_TREE_INDICATOR + mRootDN,
+ -1, this, aEntityMapping, aContext) ;
+ return (Domain)mRootDomain;
+ }
+
+ /**
+ * Returns object representing root domain.
+ *
+ * @return object representing root domain
+ */
+ public Domain getRootDomain() { return mRootDomain; }
+
+ /**
+ * Returns the error code of the LDAPException
+ * which was the source of the SPIException
+ *
+ * @param aException the SPIException
+ * @return the error code of the LDAPException inside the
+ * SPIException or 0 if SPIException does not
+ * contain an LDAPException
+ */
+ public static int getLdapErrorCode(SPIException spie) {
+ int code = 0;
+ Throwable cause = spie.getCause();
+ if (cause != null) {
+ if (cause instanceof LDAPException)
+ code = ((LDAPException)cause).getLDAPResultCode();
+ }
+ return code;
+ }
+
+ /**
+ * Creates and returns a profile with the
+ * specified display name, applicability, and priority.
+ * If the profile already exists or if a profile
+ * with that priority already exists then a
+ * <code>SPIException</code> is thrown.
+ *
+ * @param aRepository profile repository
+ * @param aDisplayName display name for the profile
+ * @param aPriority priority for profile
+ * @param aApplicability profile scope
+ * @return the <code>Profile</code> representing
+ * the created profile
+ * @throws <code>SPIException</code>
+ * if error occurs
+ */
+ public Profile createProfile(ProfileRepositoryImpl aRepository,
+ String aDisplayName,
+ Applicability aApplicability,
+ int aPriority)
+ throws SPIException {
+ String location = null;
+ try {
+ LDAPConnection connection =
+ ((LdapEntity)aRepository.getEntity())
+ .getContext().getConnection();
+ location = createProfileEntry(aRepository, aDisplayName,
+ aApplicability, aPriority,
+ connection);
+ } catch (LDAPException ldape) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY,
+ ldape);
+ }
+ return new LdapProfile(location, aRepository, aDisplayName,
+ aApplicability, aPriority);
+ }
+
+ /**
+ * Creates a profile entry.
+ *
+ * @param aRepository profile repository
+ * @param aDisplayName display name for the profile
+ * @param aApplicability profile scope
+ * @param aPriority priority for profile
+ * @param aConnection LDAP connection
+ * @throws <code>LDAPException</code> if LDAP
+ * error occurs
+ */
+ private String createProfileEntry(
+ ProfileRepository aRepository, String aDisplayName,
+ Applicability aApplicability, int aPriority,
+ LDAPConnection aConnection)
+ throws LDAPException {
+ /* First off, try to find a suitable name for the profile
+ if we can afford it. */
+ String name = null ;
+ String location = null ;
+ Random randomiser = new Random() ;
+ int identifier = 0 ;
+
+ do {
+ identifier = randomiser.nextInt() ;
+ if (identifier < 0) { identifier = -identifier ; }
+ name = String.valueOf(randomiser.nextInt()) ;
+ location = CONFIG_NAMING_ATTR + name +
+ LdapEntity.LDAP_SEPARATOR +
+ ((LdapProfileRepository)aRepository).getLocation() ;
+ } while (entryExists(location, aConnection)) ;
+ /* Then create the entry. */
+ LDAPAttributeSet profileAttrs = new LDAPAttributeSet();
+ String [] keyValues = new String [2] ;
+
+ keyValues [0] = DISPLAY_NAME_KEY + aDisplayName ;
+ keyValues [1] = APPLICABILITY_KEY +
+ aApplicability.getStringValue() ;
+ try {
+ profileAttrs.add(new LDAPAttribute(LDAP_OBJCLASS,
+ PROFILE_MAPPING.mObjectClass));
+ profileAttrs.add(new LDAPAttribute(PRIORITY_ATTR,
+ Integer.toString(aPriority)));
+ profileAttrs.add(new LDAPAttribute(KEYVALUE_ATTR, keyValues)) ;
+ profileAttrs.add(PROFILE_MAPPING.mServiceIdAttr) ;
+ addEntry(location, profileAttrs, aConnection);
+ } catch (LDAPException e1) {
+ if (e1.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
+ try {
+ LdapEntity entity =
+ (LdapEntity)aRepository.getEntity();
+ String entityServiceEntry =
+ ensureServiceEntryExistsForEntry(
+ entity.getLocation(), aConnection);
+ // ensure _GlobalPolicyGroups_ container exists
+ StringBuffer containerBuf = new StringBuffer();
+ containerBuf.append(CONFIG_NAMING_ATTR);
+ containerBuf.append(LdapProfileRepository.GLOBAL_PROFILE_CONTAINER);
+ containerBuf.append(LdapEntity.LDAP_SEPARATOR);
+ containerBuf.append(entityServiceEntry);
+ String containerDN = containerBuf.toString();
+ try {
+ aConnection.read(containerDN);
+ } catch (LDAPException e2) {
+ if (e2.getLDAPResultCode() ==
+ LDAPException.NO_SUCH_OBJECT) {
+ LDAPAttributeSet tmpSet =
+ new LDAPAttributeSet();
+ tmpSet.add(new LDAPAttribute(LDAP_OBJCLASS,
+ CONTAINER_MAPPING.mObjectClass));
+ tmpSet.add(CONTAINER_MAPPING.mServiceIdAttr);
+ addEntry(containerDN, tmpSet, aConnection);
+ } else {
+ throw e2;
+ }
+ }
+ addEntry(location, profileAttrs, aConnection);
+ } catch (SPIException spie) {
+ throw e1;
+ }
+ } else {
+ throw e1;
+ }
+ }
+ return location;
+ }
+
+ /**
+ * Finds a profile object given its repository and displayname
+ *
+ * @param aRepository profile repository
+ * @param aDisplayName display name for profile
+ * @return object representing the profile
+ * or null if not found
+ * @throws <code>SPIException/code> if error
+ * occurs
+ */
+ public Profile findProfile(LdapProfileRepository aRepository,
+ String aDisplayName)
+ throws SPIException {
+ Profile profile = null;
+ StringBuffer filter = new StringBuffer(BUFFER_LENGTH);
+ filter.append("(&(");
+ filter.append(KEYVALUE_ATTR);
+ filter.append("=");
+ filter.append(DISPLAY_NAME_KEY);
+ filter.append(aDisplayName);
+ filter.append("))");
+ Vector settings = null;
+ try {
+ settings = performSearch(
+ aRepository.getLocation(),
+ true, filter.toString(),
+ ALL_PROFILE_ATTRS,
+ true, false,
+ null, false,
+ ((LdapEntity)aRepository.getEntity()).getContext());
+ } catch (SPIException spie) {
+ int error = getLdapErrorCode(spie);
+ if ( (error == LDAPException.NO_RESULTS_RETURNED)
+ || (error == LDAPException.NO_SUCH_ATTRIBUTE)
+ || (error == LDAPException.NO_SUCH_OBJECT)) {
+ settings = null;
+ }
+ else {
+ throw spie;
+ }
+ }
+ if (settings == null || settings.isEmpty()) {
+ if (isVersion1) {
+ // get Local Profile if any
+ Profile tmpProfile = aRepository.getProfile(
+ aRepository.getLocalProfileId());
+ if ((tmpProfile != null) &&
+ (tmpProfile.getDisplayName().equals(aDisplayName))) {
+ profile = tmpProfile;
+ }
+ }
+ }
+ else {
+ profile = getProfileObject(aRepository, (Hashtable)settings.get(0));
+ }
+ return profile;
+ }
+
+ /**
+ * Takes the attribute values returned for a profile
+ * entry and returns a <code>Profile</code> object.
+ *
+ * @param aRepository profile repository
+ * @param aAttrValues collection containing required attribute
+ * values
+ * @return <code>LdapProfile</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Profile getProfileObject(
+ ProfileRepository aRepository, Hashtable aAttrValues)
+ throws SPIException {
+ String dn = null, displayName = null, priority = null;
+ String lastModified = null, authorDN = null, comment = null;
+ Applicability applicability = Applicability.UNKNOWN;
+ int priorityInt = ProfileImpl.UNDEFINED_PRIORITY;
+ Vector values = (Vector) aAttrValues.get(DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ dn = (String)values.get(0);
+ }
+ values = (Vector) aAttrValues.get(PRIORITY_ATTR);
+ if (values != null && !values.isEmpty()) {
+ priority = (String)values.get(0);
+ }
+ try {
+ priorityInt = Integer.parseInt(priority);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ values = (Vector) aAttrValues.get(MODIFY_TIMESTAMP_ATTR);
+ if (values != null && !values.isEmpty()) {
+ lastModified = (String)values.get(0);
+ }
+ values = (Vector) aAttrValues.get(MODIFY_AUTHOR_ATTR);
+ if (values != null && !values.isEmpty()) {
+ authorDN = (String)values.get(0);
+ }
+ values = (Vector) aAttrValues.get(KEYVALUE_ATTR);
+ if (values != null && !values.isEmpty()) {
+ String valuesArray[] =
+ getValuesForKey(values, DISPLAY_NAME_KEY);
+ if (valuesArray.length != 0) {
+ displayName = valuesArray[0];
+ }
+ values = (Vector) aAttrValues.get(KEYVALUE_ATTR);
+ valuesArray =
+ getValuesForKey(values, APPLICABILITY_KEY);
+ if (valuesArray.length != 0) {
+ applicability =
+ Applicability.getApplicability(valuesArray[0]);
+ }
+ valuesArray =
+ getValuesForKey(values, COMMENT_KEY);
+ if (valuesArray.length != 0) {
+ comment = valuesArray[0];
+ }
+ }
+ if (dn == null || displayName == null || lastModified == null
+ || applicability.equals(Applicability.UNKNOWN)) {
+ return null;
+ }
+ // a priority of 0 is accepted for LocalProfiles only
+ // (and only in Version1)
+ if (priorityInt <= ProfileImpl.UNDEFINED_PRIORITY) {
+ if (isVersion1) {
+ if (!LdapProfile.isLocalProfileDN(dn)) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+ ProfileRepositoryImpl repository = (ProfileRepositoryImpl)aRepository;
+ if (applicability.equals(Applicability.HOST)) {
+ ProfileRepositoryImpl rootDomainRepository =
+ (ProfileRepositoryImpl)mRootDomain.getProfileRepository();
+ if (repository.getId().equals(rootDomainRepository.getId())) {
+ repository = rootDomainRepository;
+ }
+ }
+ LdapProfile retCode = new LdapProfile(dn, repository, displayName,
+ applicability, priorityInt);
+ retCode.setLastModified(lastModified);
+ Entity author = null;
+ if (mRootOrganization != null) {
+ author = mRootOrganization.getEntity(authorDN);
+ }
+ if ((author == null) && (mRootDomain != null)) {
+ author = mRootDomain.getEntity(authorDN);
+ }
+ retCode.setAuthor(author);
+ retCode.setExistingComment(comment);
+ return retCode;
+ }
+
+ /**
+ * Takes the attribute values returned for a policy
+ * entry and returns a <code>Policy</code> object.
+ *
+ * @param aId id for the policy
+ * @param aProfile profile
+ * @param aAttrValues collection containing required attribute
+ * values
+ * @return <code>LdapPolicy</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Policy getPolicyObject(String aId, ProfileImpl aProfile,
+ Hashtable aAttrValues)
+ throws SPIException {
+ if (aProfile == null || aAttrValues == null) {
+ return null;
+ }
+ String dn = null, blob = null, lastModified = null;
+ Vector values = (Vector) aAttrValues.get(DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ dn = (String)values.get(0);
+ }
+ if (aId == null) {
+ values = (Vector) aAttrValues.get(ORG_UNIT_NAMING_ATTR);
+ if (values != null && !values.isEmpty()) {
+ aId = (String)values.get(0);
+ if (aId == null) {
+ return null;
+ } else {
+ aId = mPolicyIdParser.getOutputFormat(aId) ;
+ }
+ }
+ }
+ values = (Vector) aAttrValues.get(MODIFY_TIMESTAMP_ATTR);
+ if (values != null && !values.isEmpty()) {
+ lastModified = (String)values.get(0);
+ }
+ values = (Vector) aAttrValues.get(KEYVALUE_ATTR);
+ if (values != null && !values.isEmpty()) {
+ String valuesArray[] =
+ getValuesForKey(values, APOC_BLOB_KEY);
+ if (valuesArray.length != 0) {
+ blob = valuesArray[0];
+ }
+ }
+ if (dn == null || blob == null || lastModified == null) {
+ return null;
+ }
+ LdapPolicy retCode = new LdapPolicy(aId, blob,
+ Timestamp.getMillis(lastModified), dn, aProfile);
+ return retCode;
+ }
+
+ /**
+ * Takes the attribute values returned for a policy
+ * entry and returns a <code>PolicyInfo</code> object.
+ *
+ * @param aProfile profile
+ * @param aAttrValues collection containing required attribute
+ * values
+ * @return <code>PolicyInfo</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private PolicyInfo getPolicyInfoObject(ProfileImpl aProfile,
+ Hashtable aAttrValues)
+ throws SPIException {
+ if (aProfile == null || aAttrValues == null) {
+ return null;
+ }
+ String id = null, lastModified = null;
+ Vector values = (Vector) aAttrValues.get(ORG_UNIT_NAMING_ATTR);
+ if (values != null && !values.isEmpty()) {
+ id = (String)values.get(0);
+ if (id == null) {
+ return null;
+ } else {
+ id = mPolicyIdParser.getOutputFormat(id) ;
+ }
+ }
+ values = (Vector) aAttrValues.get(MODIFY_TIMESTAMP_ATTR);
+ if (values != null && !values.isEmpty()) {
+ lastModified = (String)values.get(0);
+ }
+ if (lastModified == null) {
+ return null;
+ }
+ PolicyInfo retCode = new PolicyInfo(id, aProfile.getId(),
+ Timestamp.getMillis(lastModified));
+ return retCode;
+ }
+
+ /**
+ * Checks if another profile of this scope and with
+ * this priority already exists. If it does then a
+ * <code>SPIException</code> is thrown.
+ *
+ * @param aRepository the profile repository
+ * @param aApplicability profile scope
+ * @param aPriority the priority
+ * @param aContext client context
+ * @throws <code>SPIException</code> if priority already
+ * in use
+ */
+ public void checkForPriorityConflict(ProfileRepository aRepository,
+ Applicability aApplicability, int aPriority)
+ throws SPIException {
+ StringBuffer location = new StringBuffer(BUFFER_LENGTH);
+ StringBuffer filter = new StringBuffer(BUFFER_LENGTH);
+ filter.append("(&");
+ addApplicabilityFilter(filter, aApplicability);
+ filter.append("(");
+ filter.append(PRIORITY_ATTR);
+ filter.append("=");
+ filter.append(aPriority);
+ filter.append("))");
+ String []attributes = new String[1];
+ attributes[0] = PRIORITY_ATTR;
+ Vector profiles = null;
+ try {
+ profiles = performSearch(
+ ((LdapProfileRepository)aRepository).getLocation(),
+ RECURSIVE_SEARCH, filter.toString(),
+ attributes,
+ false, false,
+ null, false,
+ ((LdapEntity)aRepository.getEntity()).getContext());
+ } catch (SPIException spie) {
+ int error = getLdapErrorCode(spie);
+ if ( (error == LDAPException.NO_RESULTS_RETURNED)
+ || (error == LDAPException.NO_SUCH_ATTRIBUTE)
+ || (error == LDAPException.NO_SUCH_OBJECT) ){
+ return;
+ }
+ else {
+ throw spie;
+ }
+ }
+ if (profiles != null && !profiles.isEmpty()) {
+ throw new InvalidPriorityException(
+ InvalidPriorityException.USED_PRIORITY_KEY,
+ aPriority);
+ }
+ }
+
+ /**
+ * Returns a list of the profile priorities already
+ * existing for this scope in the profile repository.
+ *
+ * @param aRepository profile repository
+ * @param aApplicability scope
+ * @return <code>Vector</code> listing existing
+ * profile priorities for this scope
+ * @throws <code>SPIException</code> if
+ * the priorities contain a duplicate
+ */
+ public Iterator getProfilePriorities(
+ ProfileRepositoryImpl aRepository,
+ Applicability aApplicability)
+ throws SPIException {
+ Vector retCode = new Vector();
+ if (aApplicability.equals(Applicability.UNKNOWN)) {
+ return retCode.iterator();
+ }
+ StringBuffer filter = new StringBuffer(BUFFER_LENGTH);
+ filter.append("(&");
+ addApplicabilityFilter(filter, aApplicability);
+ filter.append("(");
+ filter.append(PRIORITY_ATTR);
+ filter.append("=*");
+ filter.append(")");
+ filter.append(")");
+ String[] attributes = new String[1];
+ attributes[0] = PRIORITY_ATTR;
+ Vector settings = null;
+ try {
+ settings = performSearch(
+ ((LdapProfileRepository)aRepository).getLocation(),
+ false, filter.toString(),
+ attributes,
+ false, false,
+ null, false,
+ ((LdapEntity)aRepository.getEntity()).getContext());
+ } catch (SPIException spie) {
+ int error = getLdapErrorCode(spie);
+ if ( (error == LDAPException.NO_RESULTS_RETURNED)
+ || (error == LDAPException.NO_SUCH_ATTRIBUTE)
+ || (error == LDAPException.NO_SUCH_OBJECT) ){
+ return retCode.iterator();
+ }
+ else {
+ throw spie;
+ }
+ }
+ if (settings == null || settings.isEmpty()) {
+ return retCode.iterator();
+ }
+ String priority = null;
+ for (int i = 0; i < settings.size(); ++i) {
+ Integer priorityInt;
+ Hashtable groupAttributes = (Hashtable)settings.get(i);
+ Vector values = (Vector) groupAttributes.get(PRIORITY_ATTR);
+ if (values != null && !values.isEmpty()) {
+ priority = (String)values.get(0);
+ try {
+ priorityInt = new Integer(priority);
+ retCode.add(priorityInt);
+ } catch (NumberFormatException ignore) { }
+ }
+ }
+ return retCode.iterator();
+ }
+
+ /**
+ * Deletes the profile from the LDAP server.
+ *
+ * @param aRepository profile repository
+ * @param aProfile profile to be deleted
+ * @param aContext client context
+ */
+ public void destroyProfile(ProfileRepositoryImpl aRepository,
+ ProfileImpl aProfile) throws SPIException {
+ LdapClientContext context = ((LdapEntity)aRepository.getEntity())
+ .getContext();
+ String location = ((LdapProfile)aProfile).getLocation();
+ try {
+ deleteEntry(location, context);
+ } catch (LDAPException ldape) {
+ int error = ldape.getLDAPResultCode();
+ if (error == LDAPException.NO_SUCH_OBJECT) {
+ throw new InvalidProfileException(
+ InvalidProfileException.NO_EXIST_PROFILE_KEY,
+ aProfile.getId(), ldape);
+ } else if (error == LDAPException.NOT_ALLOWED_ON_NONLEAF) {
+ // need to delete components first
+ try {
+ LDAPSearchResults results = doSearch(location,
+ false,
+ LDAP_OBJCLASS + "=" + SUNSERVICE_COMPONENT_OBJCLASS,
+ null, false, context);
+ while (results.hasMoreElements()) {
+ LDAPEntry entry = results.next();
+ deleteEntry(entry.getDN(), context);
+ }
+ //then delete profile
+ deleteEntry(location, context);
+ } catch (LDAPException ldape1) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY,
+ ldape1);
+ }
+ } else {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY,
+ ldape);
+ }
+ }
+ }
+
+ /**
+ * Returns a boolean indicating if the entity has write
+ * access for this profile repository.
+ *
+ * @param aRepository profile repository
+ * @param aEntity entity
+ * @return <code>true</code> if the entity has write access
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasWriteAccess(ProfileRepositoryImpl aRepository,
+ Entity aEntity) throws SPIException{
+ LdapClientContext context = ((LdapEntity)aEntity).getContext();
+
+ try {
+ String profileId = createProfileEntry(
+ aRepository, "__TestGroupDoNotUse__",
+ Applicability.USER, ProfileImpl.UNDEFINED_PRIORITY,
+ context.getConnection());
+ context.getConnection().delete(profileId);
+ } catch (LDAPException ldape) {
+ if (ldape.getLDAPResultCode() !=
+ LDAPException.INSUFFICIENT_ACCESS_RIGHTS) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY,
+ ldape);
+ }
+ return false ;
+ }
+ return true ;
+ }
+ /**
+ * Returns the profile that matches the id.
+ *
+ * @param aRepository profile repository
+ * @param aId id for the required profile
+ * @return <code>Profile</code> matching this id
+ * or null if one does not exist
+ * @throws IllegalReadException if LDAP error occurs
+ * @throws SPIException if error occurs
+ */
+ public Profile getProfile(ProfileRepositoryImpl aRepository,
+ String aId) throws SPIException {
+ if (aId == null) { return null; }
+ Hashtable valuesTable = null;
+ try {
+ valuesTable = getAttributeValueTable(aId,
+ true, ALL_PROFILE_ATTRS,
+ ((LdapEntity)aRepository.getEntity()).getContext());
+ } catch (LDAPException ldape) {
+ if (ldape.getLDAPResultCode() ==
+ LDAPException.NO_SUCH_OBJECT) {
+ return null;
+ }
+ else {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ }
+ return getProfileObject(aRepository, valuesTable);
+ }
+
+ private String getEntityIdFromProfileId(String aProfileId) {
+ if (aProfileId == null) { return null; }
+ String [] dnComponents = LDAPDN.explodeDN(aProfileId, false);
+ if (dnComponents == null
+ || dnComponents.length < NUMBER_OF_SERVICE_MAPPING_ELEMENTS+2) {
+ return null;
+ }
+ StringBuffer buf = new StringBuffer();
+ int start = 1 + NUMBER_OF_SERVICE_MAPPING_ELEMENTS;
+ /* exclude legacy global container element */
+ if (dnComponents[start].equalsIgnoreCase(
+ CONFIG_NAMING_ATTR + SERVICES)) {
+ start++;
+ }
+ buf.append(dnComponents[start]);
+ for (int i = start + 1; i < dnComponents.length; ++i) {
+ buf.append(LdapEntity.LDAP_SEPARATOR);
+ buf.append(dnComponents[i]);
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns the profile that matches the id.
+ *
+ * @param aId id for the required profile
+ * @return <code>Profile</code> matching this id
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getProfile(String aId) throws SPIException {
+ if (aId == null) { return null; }
+ String entityId = getEntityIdFromProfileId(aId);
+ Entity entity = null;
+ if (mRootOrganization != null) {
+ entity = mRootOrganization.getEntity(entityId);
+ }
+ if ((entity == null) && (mRootDomain != null)) {
+ entity = mRootDomain.getEntity(entityId);
+ }
+ if (entity == null) { return null; }
+ return getProfile(
+ (ProfileRepositoryImpl)entity.getProfileRepository(),
+ aId);
+ }
+
+ /**
+ * Returns the profiles that match the filter string.
+ *
+ * @param aRepository profile repository
+ * then all profiles required
+ * @param aApplicability scope of profiles required
+ * @return TreeSet of profiles matching
+ * the filter
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public TreeSet getProfiles(LdapProfileRepository aRepository,
+ Applicability aApplicability)
+ throws SPIException {
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ tmpBuf.append("(&(");
+ tmpBuf.append(CONFIG_NAMING_ATTR);
+ tmpBuf.append(LDAP_WILDCARD);
+ tmpBuf.append(")");
+ tmpBuf.append("(");
+ tmpBuf.append(SUNSERVICEID_ATTR);
+ tmpBuf.append("=");
+ tmpBuf.append(SUNSERVICEID_PROFILE);
+ tmpBuf.append("))");
+ Vector profiles = null;
+
+ try {
+ profiles = performSearch(
+ aRepository.getLocation(),
+ true, tmpBuf.toString(),
+ ALL_PROFILE_ATTRS,
+ true, false,
+ null, false,
+ ((LdapEntity)aRepository.getEntity()).getContext());
+ } catch (SPIException spie) {
+ if (getLdapErrorCode(spie) != LDAPException.NO_SUCH_OBJECT) {
+ throw spie;
+ }
+ }
+ TreeSet profilesTree = new TreeSet(new LdapProfileComparator());
+ if (profiles != null) {
+ ProfileImpl tmpProfile = null;
+ int nbProfiles = profiles.size();
+ for (int i = 0; i < nbProfiles; ++i) {
+ tmpProfile = (ProfileImpl)getProfileObject(aRepository,
+ (Hashtable)profiles.get(i));
+ if (tmpProfile == null) {
+ continue;
+ }
+ boolean includeProfile = false;
+ Applicability tmpApp = tmpProfile.getApplicability();
+ if (tmpApp.equals(Applicability.ALL)){
+ includeProfile = true;
+ }
+ else if (tmpApp.equals(Applicability.HOST)
+ || tmpApp.equals(Applicability.USER)) {
+ if ( aApplicability.equals(Applicability.ALL)
+ || aApplicability.equals(tmpApp)) {
+ includeProfile = true;
+ }
+ }
+ if (includeProfile) {
+ profilesTree.add(tmpProfile);
+ }
+ }
+ }
+ if (isVersion1) {
+ // include Local Profile if any
+ Profile tmpProfile = aRepository.getProfile(
+ aRepository.getLocalProfileId());
+ if (tmpProfile != null) {
+ profilesTree.add(tmpProfile);
+ }
+ }
+ return profilesTree;
+ }
+
+ /**
+ * Returns all the profiles
+ *
+ * @param aPolicyManager the PolicyManager object
+ * @return <code>Iterator</code> over all the Profiles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getAllProfiles(PolicySource aPolicySource, LdapEntity startingEntity,
+ Applicability applicability)
+ throws SPIException {
+ Vector retCode = new Vector();
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ tmpBuf.append("(&(");
+ tmpBuf.append(LDAP_OBJCLASS);
+ tmpBuf.append("=");
+ tmpBuf.append(SUNSERVICE_COMPONENT_OBJCLASS);
+ tmpBuf.append(")");
+ tmpBuf.append("(");
+ tmpBuf.append(CONFIG_NAMING_ATTR);
+ tmpBuf.append(LDAP_WILDCARD);
+ tmpBuf.append(")");
+ tmpBuf.append("(");
+ tmpBuf.append(SUNSERVICEID_ATTR);
+ tmpBuf.append("=");
+ tmpBuf.append(SUNSERVICEID_PROFILE);
+ tmpBuf.append("))");
+ Vector profiles = null;
+
+ try {
+ profiles = performSearch(
+ startingEntity.getLocation(),
+ true, tmpBuf.toString(),
+ ALL_PROFILE_ATTRS,
+ true, false,
+ null, false,
+ startingEntity.getContext());
+ } catch (SPIException spie) {
+ if (getLdapErrorCode(spie) == LDAPException.NO_SUCH_OBJECT) {
+ return retCode.iterator();
+ } else {
+ throw spie;
+ }
+ }
+ if (profiles == null || profiles.isEmpty()) {
+ return retCode.iterator();
+ }
+
+ Hashtable repositories = new Hashtable();
+ TreeSet profilesTree =
+ new TreeSet(new LdapProfileComparator());
+ ProfileImpl profile = null;
+ int nbProfiles = profiles.size();
+ for (int i = 0; i < nbProfiles; ++i) {
+ Hashtable attrValues = (Hashtable)profiles.get(i);
+ // reuse or create a ProfileRepository for the Profile
+ String dn = null;
+ Vector values = (Vector) attrValues.get(DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ dn = (String)values.get(0);
+ }
+ if (dn == null) {
+ continue;
+ }
+ String entityId = getEntityIdFromProfileId(dn);
+ if (aPolicySource.getEntity(entityId) == null) {
+ continue;
+ }
+ LdapProfileRepository repository =
+ (LdapProfileRepository)repositories.get(entityId);
+ if (repository == null) {
+ repository = new LdapProfileRepository(entityId,
+ aPolicySource);
+ repositories.put(entityId, repository);
+ }
+ profile = (ProfileImpl)getProfileObject(repository,
+ attrValues);
+ if (profile == null) {
+ continue;
+ }
+ // filter profiles after applicability
+ if (!applicability.equals(Applicability.ALL)
+ && !applicability.equals(profile.getApplicability())) {
+ continue;
+ }
+ profilesTree.add(profile);
+ }
+ return profilesTree.iterator();
+ }
+
+ /**
+ * Returns an <code>Iterator</code> of <code>Profile</code>s
+ * assigned to an entity.
+ * The <code>Iterator</code> is ordered by profile priority,
+ * with the most specific profile as the last element.
+ *
+ * @param aEntity entity whose assigned profiles are
+ * required
+ * @return <code>Iterator</code> of profiles
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ public Iterator getAssignedProfiles(Entity aEntity)
+ throws SPIException {
+ LdapEntity entity = (LdapEntity)aEntity;
+ Vector policyList = new Vector();
+ Vector assignedProfiles = new Vector();
+ String []attributes = new String[1];
+ attributes[0] = KEYVALUE_ATTR;
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ tmpBuf.append(getServiceEntryDN()).append(
+ LdapEntity.LDAP_SEPARATOR).append(
+ entity.getLocation());
+ try {
+ policyList = getAttributeValueList(tmpBuf.toString(),
+ attributes, entity.getContext());
+ } catch (LDAPException ldape) {
+ int error = ldape.getLDAPResultCode();
+ if ( (error != LDAPException.NO_RESULTS_RETURNED)
+ && (error != LDAPException.NO_SUCH_ATTRIBUTE)
+ && (error != LDAPException.NO_SUCH_OBJECT) ) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY,
+ ldape);
+ }
+ }
+ if (policyList == null || policyList.isEmpty()) {
+ return assignedProfiles.iterator();
+ }
+ String [] assignedValues = getValuesForKey(policyList,
+ ASSIGNED_KEY);
+ for (int i = 0; i < assignedValues.length; ++i) {
+ String profileDN = assignedValues[i];
+ if (profileDN != null) {
+ Profile profile = null;
+ try {
+ profile = getProfile(profileDN);
+ if (profile != null) {
+ assignedProfiles.add(profile);
+ }
+ } catch (Exception ignore) {
+ /* problem creating profile, so omit */
+ }
+ }
+ }
+ // for compatiblity with APOC 1, add Local Profile if any
+ if (isVersion1) {
+ LdapProfileRepository rep =
+ (LdapProfileRepository)entity.getProfileRepository();
+ String localId = rep.getLocalProfileId();
+ Profile localProfile = rep.getProfile(localId);
+ if (localProfile != null) {
+ boolean profileIncluded = false;
+ Iterator iterProfiles = assignedProfiles.iterator();
+ while (iterProfiles.hasNext()) {
+ Profile profile = (Profile)iterProfiles.next();
+ if (profile.equals(localProfile)) {
+ profileIncluded = true;
+ break;
+ }
+ }
+ if (!profileIncluded) {
+ assignedProfiles.add(localProfile);
+ }
+ }
+ }
+ return assignedProfiles.iterator();
+ }
+
+ /**
+ * Assigns a profile to this entity.
+ *
+ * @param aProfile profile to assign
+ * @param aEntity entity to which the profile is to
+ * to be assigned
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void assignProfile(Profile aProfile, Entity aEntity)
+ throws SPIException {
+ if (aProfile == null) { return; }
+ String attribute = KEYVALUE_ATTR;
+ try {
+ boolean entryExists = entryExists(((LdapProfile)aProfile).getLocation(),
+ ((LdapEntity)aEntity).getContext());
+ if (!entryExists) {
+ throw new InvalidProfileException(
+ InvalidProfileException.NO_EXIST_PROFILE_KEY,
+ aProfile.getId());
+ }
+ } catch (LDAPException ldape) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ String values[] =
+ {ASSIGNED_KEY + ((LdapProfile)aProfile).getLocation().toLowerCase() };
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ tmpBuf.append(getServiceEntryDN());
+ tmpBuf.append(LdapEntity.LDAP_SEPARATOR);
+ tmpBuf.append(((LdapEntity)aEntity).getLocation());
+ addValuesToMultiValuedAttribute(tmpBuf.toString(),
+ attribute, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aEntity).getContext()) ;
+
+ }
+
+ /**
+ * Unassigns a profile to this entity.
+ *
+ * @param aProfile profile to unassign
+ * @param aEntity entity that currently has the profile
+ * assigned
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void unassignProfile(Profile aProfile,
+ Entity aEntity) throws SPIException {
+ if (aProfile == null) { return; }
+ String values [] = { ASSIGNED_KEY +
+ ((LdapProfile)aProfile).getLocation() };
+ values[0] = values[0].toLowerCase();
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ tmpBuf.append(getServiceEntryDN()).append(
+ LdapEntity.LDAP_SEPARATOR).append(
+ ((LdapEntity)aEntity).getLocation());
+ removeMultiValuedAttributeValues(tmpBuf.toString(),
+ KEYVALUE_ATTR, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aEntity).getContext()) ;
+ }
+
+ /**
+ * Sets the priority for this profile.
+ *
+ * @param aProfile profile
+ * @param aPriority priority for this profile
+ * @throws SPIException if error occurs
+ * @throws InvalidPriorityException if aPriority invalid or in use
+ */
+ public void setProfilePriority(ProfileImpl aProfile,
+ int aPriority) throws SPIException {
+ if (aPriority <= ProfileImpl.UNDEFINED_PRIORITY) {
+ throw new InvalidPriorityException(
+ InvalidPriorityException.INVALID_PRIORITY_KEY,
+ aPriority);
+ }
+ checkForPriorityConflict(aProfile.getProfileRepository(),
+ aProfile.getApplicability(), aPriority);
+ String attributes[] = { PRIORITY_ATTR } ;
+ String values [] = { Integer.toString(aPriority) };
+ fillAttributes(((LdapProfile)aProfile).getLocation(),
+ attributes, values,
+ SUNSERVICE_COMPONENT_OBJCLASS, ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext()) ;
+ }
+
+ /**
+ * Sets the display name for this profile.
+ *
+ * @param aProfile profile
+ * @param aDisplayName new display name for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setProfileDisplayName(ProfileImpl aProfile,
+ String aDisplayName) throws SPIException {
+ String values[] = { DISPLAY_NAME_KEY +
+ aProfile.getDisplayName() };
+ removeMultiValuedAttributeValues(
+ ((LdapProfile)aProfile).getLocation(),
+ KEYVALUE_ATTR, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext()) ;
+ values[0] = DISPLAY_NAME_KEY + aDisplayName;
+ addValuesToMultiValuedAttribute(
+ ((LdapProfile)aProfile).getLocation(),
+ KEYVALUE_ATTR, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext()) ;
+ }
+
+ /**
+ * Sets the comment for this profile. If the new
+ * comment is null then the existing comment is removed.
+ *
+ * @param aProfile profile object
+ * @param aComment comment as a String
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setProfileComment(ProfileImpl aProfile,
+ String aComment) throws SPIException {
+ String values [] = new String[1];
+ if (aProfile.getComment() != null) {
+ values[0] = COMMENT_KEY + aProfile.getComment();
+ removeMultiValuedAttributeValues(
+ ((LdapProfile)aProfile).getLocation(),
+ KEYVALUE_ATTR, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext()) ;
+ }
+ if (aComment != null) {
+ values[0] = COMMENT_KEY + aComment;
+ addValuesToMultiValuedAttribute(
+ ((LdapProfile)aProfile).getLocation(),
+ KEYVALUE_ATTR, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext()) ;
+ }
+ }
+
+ /**
+ * Sets the scope for this profile.
+ *
+ * @param aProfile profile
+ * @param aApplicability new scope for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setProfileApplicability(ProfileImpl aProfile,
+ Applicability aApplicability) throws SPIException{
+ String values [] = { APPLICABILITY_KEY + aProfile.getApplicability() } ;
+ removeMultiValuedAttributeValues(
+ ((LdapProfile)aProfile).getLocation(),
+ KEYVALUE_ATTR, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext()) ;
+ values[0] = APPLICABILITY_KEY + aApplicability ;
+ addValuesToMultiValuedAttribute(
+ ((LdapProfile)aProfile).getLocation(),
+ KEYVALUE_ATTR, values,
+ SUNSERVICE_COMPONENT_OBJCLASS,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext()) ;
+ }
+
+ /**
+ * Returns the entities to which this profile has been assigned.
+ *
+ * @param aProfile profile
+ * @return <code>Iterator</code> of entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getAssignedEntities(Profile aProfile)
+ throws SPIException {
+ Vector entityList = getListOfEntitiesForProfile(aProfile);
+ Vector retCode = new Vector();
+ if (!entityList.isEmpty()) {
+ int size = entityList.size();
+ for (int i = 0 ; i < size ; i++) {
+ try {
+ Hashtable attrsValues = (Hashtable)entityList.get(i);
+ Vector values =
+ (Vector)attrsValues.get(DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ String dN = (String)values.get(0);
+ Entity tmpEntity = null;
+ LdapEntity root = null;
+ if (aProfile.getApplicability().equals(
+ Applicability.HOST)) {
+ root = mRootDomain ;
+ }
+ else {
+ root = mRootOrganization ;
+ }
+ if (root != null) {
+ tmpEntity = root.getEntityFromDN(dN,
+ LdapEntityType.UNKNOWN, true, null) ;
+ if (tmpEntity != null) { retCode.add(tmpEntity) ; }
+ }
+ }
+ } catch (Exception ignore) {
+ /* cannot convert DN to EntityId, so omit from list */
+ }
+ }
+ }
+ // for compatiblity with APOC 1,
+ // add containing Entity if Local Profile
+ if (isVersion1 && ((LdapProfile)aProfile).isLocal()) {
+ Entity profileEntity = aProfile.getProfileRepository().getEntity();
+ boolean entityIncluded = false;
+ Iterator iterEntities = retCode.iterator();
+ while (iterEntities.hasNext()) {
+ Entity entity = (Entity)iterEntities.next();
+ if (entity.equals(profileEntity)) {
+ entityIncluded = true;
+ break;
+ }
+ }
+ if (!entityIncluded) {
+ retCode.add(profileEntity);
+ }
+ }
+ return retCode.iterator();
+ }
+
+ /**
+ * For a given profile return a list of entries
+ * that have this profile assigned to them.
+ *
+ * @param aProfile profile
+ * @return <code>Vector</code> listing entries for
+ * entities to which this profile
+ * is assigned
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector getListOfEntitiesForProfile(Profile aProfile)
+ throws SPIException {
+ Vector entityList = null;
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ try {
+ tmpBuf.append("(&(");
+ tmpBuf.append(LDAP_OBJCLASS);
+ tmpBuf.append("=");
+ tmpBuf.append(SUNSERVICE_COMPONENT_OBJCLASS);
+ tmpBuf.append(")(");
+ tmpBuf.append(KEYVALUE_ATTR);
+ tmpBuf.append("=");
+ tmpBuf.append(ASSIGNED_KEY);
+ tmpBuf.append(((LdapProfile)aProfile).getLocation());
+ tmpBuf.append("))");
+ entityList = performSearch(getBaseDN(),
+ RECURSIVE_SEARCH,
+ (tmpBuf.toString()).toLowerCase(),
+ null, true,
+ false, null,
+ false,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext());
+ } catch (SPIException spie) {
+ int error = getLdapErrorCode(spie);
+ if ( (error != LDAPException.NO_RESULTS_RETURNED)
+ && (error != LDAPException.NO_SUCH_ATTRIBUTE)
+ && (error != LDAPException.NO_SUCH_OBJECT) ) {
+ throw spie;
+ }
+ }
+ return entityList == null ? new Vector(): entityList;
+ }
+
+ /**
+ * Returns the requested policy object.
+ *
+ * @param aProfile the profile
+ * @param aId the id for the required policy
+ * @return the policy object
+ * @throws IllegalReadException if LDAP error occurs
+ * @throws SPIException if error occurs
+ */
+ public Policy getPolicy(ProfileImpl aProfile, String aId)
+ throws SPIException {
+ StringBuffer location = new StringBuffer(BUFFER_LENGTH);
+ location.append(CONFIG_NAMING_ATTR);
+ location.append(mPolicyIdParser.getStoredFormat(aId));
+ location.append(LdapEntity.LDAP_SEPARATOR);
+ location.append(((LdapProfile)aProfile).getLocation());
+ Hashtable policyTable = null;
+ try {
+ policyTable = getAttributeValueTable(location.toString(),
+ true, ALL_POLICY_ATTRS,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext());
+ } catch (LDAPException ldape) {
+ if (ldape.getLDAPResultCode() != LDAPException.NO_SUCH_OBJECT) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ }
+ Policy retCode = null;
+ if (policyTable != null && !policyTable.isEmpty()) {
+ retCode = getPolicyObject(aId, aProfile, policyTable);
+ }
+ return retCode;
+ }
+
+
+ /**
+ * Utility function to build the filter corresponding to a list
+ * of policy ids for a search, i.e either an overall filter,
+ * a single value one or an OR between the possible values.
+ *
+ * @param aPolicyIds array of policy ids
+ * @param aIdParser used to build stored policy ids
+ * @return filter
+ */
+ private static String buildPolicyIdFilter(Iterator aPolicyIds,
+ PolicyIdParser aIdParser) {
+ StringBuffer retCode = new StringBuffer();
+ retCode.append("(");
+ if (aPolicyIds.hasNext()) {
+ String policyId = (String)aPolicyIds.next();
+ if (aPolicyIds.hasNext()) {
+ // more than 1 element => multiple criteria
+ retCode.append("|") ;
+ retCode.append("(").append(CONFIG_NAMING_ATTR) ;
+ retCode.append(aIdParser.getStoredFormat(policyId)) ;
+ retCode.append(")") ;
+ while (aPolicyIds.hasNext()) {
+ policyId = (String)aPolicyIds.next();
+ retCode.append("(").append(CONFIG_NAMING_ATTR) ;
+ retCode.append(aIdParser.getStoredFormat(policyId)) ;
+ retCode.append(")") ;
+ }
+ } else {
+ // 1 element => simple criteria
+ retCode.append(CONFIG_NAMING_ATTR) ;
+ retCode.append(aIdParser.getStoredFormat(policyId)) ;
+ }
+ } else {
+ // 0 element => wildcard
+ retCode.append(CONFIG_NAMING_ATTR);
+ retCode.append(LDAP_WILDCARD);
+ }
+ retCode.append(")") ;
+ return retCode.toString() ;
+ }
+
+ /**
+ * Destroys a <code>Policy</code>.
+ *
+ * @param aPolicy the policy object
+ * @throws IllegalReadException if LDAP error occurs
+ * @throws SPIException if error occurs
+ * @throws NoSuchPolicyException if policy not found
+ */
+ public void destroyPolicy(Policy aPolicy)
+ throws SPIException {
+ try {
+ LdapPolicy ldapPolicy = (LdapPolicy)aPolicy;
+ LdapClientContext context =
+ ((LdapEntity)ldapPolicy.getProfile()
+ .getProfileRepository().getEntity()).getContext();
+ deleteEntry(ldapPolicy.getLocation(), context);
+ } catch (LDAPException ldape) {
+ int error = ldape.getLDAPResultCode();
+ if (error == LDAPException.NO_SUCH_OBJECT) {
+ throw new NoSuchPolicyException (aPolicy.getId());
+ } else {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY, ldape);
+ }
+ }
+ }
+
+ /**
+ * Adds policy entry for a given profile, and
+ * returns the DN of this entry.
+ *
+ * @param aProfile profile
+ * @param aStoredFormatId name of the component
+ * @param aConnection client LDAP connection
+ * @return DN for this entry
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ private String createPolicyEntry(ProfileImpl aProfile,
+ String aStoredFormatId,
+ LDAPConnection aConnection)
+ throws SPIException {
+ StringBuffer tmpBuf = new StringBuffer(BUFFER_LENGTH);
+ try {
+ /* create entry for policy */
+ tmpBuf.append(CONFIG_NAMING_ATTR).append(aStoredFormatId).append(
+ LdapEntity.LDAP_SEPARATOR).append(
+ ((LdapProfile)aProfile).getLocation());
+ /* add an entry for this component */
+ LDAPAttributeSet policyAttrs = new LDAPAttributeSet();
+ policyAttrs.add(new LDAPAttribute(LDAP_OBJCLASS,
+ POLICY_MAPPING.mObjectClass));
+ policyAttrs.add(POLICY_MAPPING.mServiceIdAttr);
+ addEntry(tmpBuf.toString(), policyAttrs, aConnection);
+ } catch (LDAPException ldape) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY,
+ ldape);
+ }
+ return tmpBuf.toString();
+ }
+
+ /**
+ * Check if the given profile contains any Policy
+ *
+ * @param aProfile profile to look at
+ * @return true if profile contains policies,
+ * false otherwise
+ * @throws <code>SPIException</code> if an error occurs
+ */
+ public boolean hasPolicies(ProfileImpl aProfile)
+ throws SPIException {
+ String filter = buildPolicyIdFilter(new Vector().iterator(),
+ mPolicyIdParser);
+ Vector policies = getListOfPoliciesForProfile(aProfile, filter, true);
+ return ((policies!=null) && (!policies.isEmpty()));
+ }
+
+ /**
+ * Returns an <code>Vector</code> of policy objects representing
+ * the policies present in a given profile.
+ *
+ * @param aProfile profile to look at
+ * @return list of policy objects
+ * @throws <code>SPIException</code> if an error occurs
+ */
+ public Vector getPolicies(ProfileImpl aProfile)
+ throws SPIException {
+ String filter = buildPolicyIdFilter(new Vector().iterator(),
+ mPolicyIdParser);
+ return getPolicies(aProfile, filter);
+ }
+
+ /**
+ * Returns the policies for this profile that match the specified
+ * policy ids.
+ *
+ * @param aProfile profile to look at
+ * @param aPolicyIdList list of policy ids
+ * @return list of all the policies
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector getPolicies(ProfileImpl aProfile, Iterator aPolicyIdList)
+ throws SPIException {
+ String filter = buildPolicyIdFilter(aPolicyIdList,
+ mPolicyIdParser);
+ return getPolicies(aProfile, filter);
+
+ }
+
+ /**
+ * Returns the policyInfos for this profile that match the specified
+ * policy ids.
+ *
+ * @param aProfile profile to look at
+ * @param aPolicyIdList list of policy ids
+ * @return list of all the policyInfos
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector getPolicyInfos(ProfileImpl aProfile,
+ Iterator aPolicyIdList)
+ throws SPIException {
+ String filter = buildPolicyIdFilter(aPolicyIdList,
+ mPolicyIdParser);
+ return getPolicyInfos(aProfile, filter);
+ }
+
+ /**
+ * Returns an <code>Vector</code> of policy objects representing
+ * the policies matching the search criteria present in a given
+ * profile.
+ *
+ * @param aProfile profile to look at
+ * @param aSearchFilter search filter
+ * @return list of policy objects
+ * @throws <code>SPIException</code> if an error occurs
+ */
+ private Vector getPolicies(ProfileImpl aProfile, String aSearchFilter)
+ throws SPIException {
+ Vector policies = getListOfPoliciesForProfile(aProfile,
+ aSearchFilter, false);
+ if (policies == null || policies.isEmpty()) {
+ return new Vector();
+ }
+ Vector retCode = new Vector();
+ int size = policies.size();
+ for (int i = 0 ; i < size; ++i) {
+ Policy policy = getPolicyObject(null,
+ aProfile, (Hashtable)policies.get(i));
+ if (policy != null) {
+ retCode.add(policy) ;
+ }
+ }
+ return retCode ;
+ }
+
+ /**
+ * Returns an <code>Vector</code> of PolicyInfo objects
+ * matching the search criteria present in a given
+ * profile.
+ *
+ * @param aProfile profile to look at
+ * @param aSearchFilter search filter
+ * @return list of policy objects
+ * @throws <code>SPIException</code> if an error occurs
+ */
+ private Vector getPolicyInfos(ProfileImpl aProfile, String aSearchFilter)
+ throws SPIException {
+ Vector policies = getListOfPoliciesForProfile(aProfile,
+ aSearchFilter, true);
+ if (policies == null || policies.isEmpty()) {
+ return new Vector();
+ }
+ Vector retCode = new Vector();
+ int size = policies.size();
+ for (int i = 0 ; i < size; ++i) {
+ PolicyInfo policy = getPolicyInfoObject(aProfile,
+ (Hashtable)policies.get(i));
+ if (policy != null) {
+ retCode.add(policy) ;
+ }
+ }
+ return retCode ;
+ }
+
+ /**
+ * Returns an <code>Vector</code> of hashtables representing
+ * the policies matching the search criteria present in a given
+ * profile.
+ *
+ * @param aProfile profile to look at
+ * @param aSearchFilter search filter
+ * @param aTimestampOnly indicate if search for timestamp of policy only
+ * or all attributes of policy
+ * @return list of policy hashtables
+ * @throws <code>SPIException</code> if an error occurs
+ */
+ public Vector getListOfPoliciesForProfile(ProfileImpl aProfile,
+ String aSearchFilter, boolean aTimestampOnly)
+ throws SPIException {
+ if (aProfile == null) {
+ throw new IllegalArgumentException();
+ }
+ Vector policies = null ;
+ String[] attrs = aTimestampOnly ? TIMEONLY_POLICY_ATTRS
+ : ALL_POLICY_ATTRS;
+ try {
+ policies = performSearch(
+ ((LdapProfile) aProfile).getLocation(),
+ false, aSearchFilter,
+ attrs,
+ true, false,
+ new BooleanReturnValue(false),
+ false,
+ ((LdapEntity)aProfile.getProfileRepository()
+ .getEntity()).getContext()) ;
+ } catch (SPIException spie) {
+ if (getLdapErrorCode(spie) == LDAPException.NO_SUCH_OBJECT) {
+ return new Vector();
+ } else {
+ throw spie;
+ }
+ }
+ return policies;
+ }
+
+ /**
+ * Stores a policy.
+ *
+ * @param aProfile the profile
+ * @param aPolicy policy
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void storePolicy(ProfileImpl aProfile, Policy aPolicy)
+ throws SPIException {
+ LDAPConnection connection =
+ ((LdapEntity)aProfile.getProfileRepository().getEntity())
+ .getContext().getConnection();
+ // we have to calculate the dn for the policy to be able
+ // to delete it, even though it will be calculated again
+ // in createPolicyEntry
+ String policyId = aPolicy.getId();
+ String storedId = mPolicyIdParser.getStoredFormat(policyId);
+ StringBuffer locationBuf =
+ new StringBuffer(BUFFER_LENGTH);
+ locationBuf.append(CONFIG_NAMING_ATTR).append(storedId)
+ .append(LdapEntity.LDAP_SEPARATOR)
+ .append(((LdapProfile)aProfile).getLocation());
+ String dn = locationBuf.toString();
+ if (aPolicy.getData() == null || aPolicy.getData().length() == 0) {
+ try {
+ connection.delete(dn) ;
+ } catch (LDAPException ldape) {
+ if (ldape.getLDAPResultCode() !=
+ LDAPException.NO_SUCH_OBJECT) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY, ldape);
+ }
+ }
+ }
+ else {
+ Change [] update = new Change [1] ;
+
+ update [0] = new Change(KEYVALUE_ATTR, APOC_BLOB_KEY + aPolicy.getData()) ;
+ try {
+ writeAttributes(dn, SUNSERVICE_COMPONENT_OBJCLASS,
+ update, false, connection) ;
+ }
+ catch (SPIException spie) {
+ if (getLdapErrorCode(spie)
+ == LDAPException.NO_SUCH_OBJECT) {
+ createPolicyEntry(aProfile, storedId, connection) ;
+ writeAttributes(dn, SUNSERVICE_COMPONENT_OBJCLASS,
+ update, false, connection) ;
+ }
+ else { throw spie; }
+ }
+ }
+ }
+
+ /**
+ * Adds policy entry.
+ *
+ * @param aPolicy policy object
+ * @param aConnection client LDAP connection
+ * @return <code>true</code> if the entry is
+ * present, otherwise <code>false</code>
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ private void createPolicyEntry(LdapPolicy aPolicy,
+ LDAPConnection aConnection)
+ throws SPIException{
+ Profile existingProfile =
+ findProfile(
+ (LdapProfileRepository)aPolicy.getProfile()
+ .getProfileRepository(),
+ aPolicy.getProfile().getDisplayName());
+ if (existingProfile == null) {
+ try {
+ /* add the profile entry first */
+ createProfileEntry(aPolicy.getProfile().getProfileRepository(),
+ aPolicy.getProfile().getDisplayName(),
+ aPolicy.getProfile().getApplicability(),
+ aPolicy.getProfile().getPriority(),
+ aConnection);
+ } catch (LDAPException ldape) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY, ldape);
+ }
+ }
+ try {
+ /* then create entry for policy */
+ LDAPAttributeSet policyAttrs = new LDAPAttributeSet();
+ policyAttrs.add(new LDAPAttribute(LDAP_OBJCLASS,
+ POLICY_MAPPING.mObjectClass));
+ policyAttrs.add(POLICY_MAPPING.mServiceIdAttr);
+ addEntry(aPolicy.getLocation(), policyAttrs, aConnection);
+ } catch (LDAPException ldape) {
+ throw new IllegalWriteException(
+ IllegalWriteException.LDAP_WRITE_KEY, ldape);
+ }
+ }
+ /**
+ * Adds applicability filter to string buffer.
+ *
+ * @param aFilter filter buffer
+ * @param aApplicability applicability setting
+ */
+ private void addApplicabilityFilter(StringBuffer aFilter,
+ Applicability aApplicability) {
+ aFilter.append("(|(");
+ aFilter.append(KEYVALUE_ATTR);
+ aFilter.append("=");
+ aFilter.append(APPLICABILITY_KEY);
+ aFilter.append(Applicability.STR_ALL);
+ aFilter.append(")");
+ if (aApplicability.equals(Applicability.ALL)) {
+ aFilter.append("(");
+ aFilter.append(KEYVALUE_ATTR);
+ aFilter.append("=");
+ aFilter.append(APPLICABILITY_KEY);
+ aFilter.append(Applicability.STR_USER);
+ aFilter.append(")(");
+ aFilter.append(KEYVALUE_ATTR);
+ aFilter.append("=");
+ aFilter.append(APPLICABILITY_KEY);
+ aFilter.append(Applicability.STR_HOST);
+ aFilter.append(")");
+ } else {
+ aFilter.append("(");
+ aFilter.append(KEYVALUE_ATTR);
+ aFilter.append("=");
+ aFilter.append(APPLICABILITY_KEY);
+ aFilter.append(aApplicability.getStringValue());
+ aFilter.append(")");
+ }
+ aFilter.append(")");
+ }
+
+ /**
+ * Gets the value for the modifiedtimestamp attribute
+ * for this profile.
+ *
+ * @param aProfile the profile object
+ * @return value for modifiedtimestamp
+ * attribute and author
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public ArrayList getModificationDetails(LdapProfile aProfile)
+ throws SPIException {
+ return getModificationDetails(aProfile.getLocation(),
+ ((LdapEntity)aProfile.getProfileRepository().
+ getEntity()).getContext());
+ }
+
+ /**
+ * Gets the value for the modifiedtimestamp attribute
+ * for this policy.
+ *
+ * @param aPolicy the policy object
+ * @return value for modifiedtimestamp
+ * attribute and author
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public ArrayList getModificationDetails(LdapPolicy aPolicy)
+ throws SPIException {
+ return getModificationDetails(aPolicy.getLocation(),
+ ((LdapEntity)aPolicy.getProfile().getProfileRepository().getEntity()).getContext());
+ }
+
+ /**
+ * Gets the value for the modifiedtimestamp attribute
+ * for this DN.
+ *
+ * @param aDN the DN for the entry
+ * @param aContext the client context
+ * @return String value for modifiedtimestamp
+ * attribute
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public ArrayList getModificationDetails(String aDN,
+ LdapClientContext aContext)
+ throws SPIException {
+ Vector entries = null;
+ String attributes[] = {MODIFY_TIMESTAMP_ATTR,
+ MODIFY_AUTHOR_ATTR};
+ try {
+ entries = getAttributeValueList(aDN, attributes, aContext);
+ } catch (LDAPException ldape) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ if (entries == null || entries.size() == 0) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY);
+ }
+ ArrayList retCode = new ArrayList();
+ // lastmodified timestamp
+ retCode.add(entries.get(0));
+ // author if there
+ if (entries.size() > 1) {
+ String authorDN = (String)entries.get(1);
+ if ((authorDN != null) && (mRootOrganization != null)) {
+ Entity author = mRootOrganization.getEntity(authorDN);
+ if (author != null) {
+ retCode.add(author);
+ }
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Gets the comment for this profile.
+ *
+ * @param aProfile the profile
+ * @return String value for comment
+ * @throws IllegalReadException if LDAP error occurs
+ * @throws SPIException if error occurs
+ */
+ public String getProfileComment(Profile aProfile)
+ throws SPIException {
+ Vector entries = null;
+ String attributes[] = {KEYVALUE_ATTR};
+ try {
+ entries = getAttributeValueList(
+ ((LdapProfile)aProfile).getLocation(), attributes,
+ ((LdapEntity)aProfile.getProfileRepository().getEntity()).getContext());
+ } catch (LDAPException ldape) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+ String comment = null;
+ if (entries != null || !entries.isEmpty()) {
+ String valuesArray[] =
+ getValuesForKey(entries, COMMENT_KEY);
+ if (valuesArray.length != 0) {
+ comment = valuesArray[0];
+ }
+ }
+ return comment;
+
+ }
+
+ /**
+ * Class used for converting policy ids to/from storage
+ * format.
+ */
+ public class PolicyIdParser
+ {
+ /** table matching requested policy ids
+ to the string used in the backend store */
+ Hashtable policyIds = new Hashtable();
+ /** String buffer used during conversion */
+ StringBuffer compBuf = new StringBuffer(BUFFER_LENGTH);
+ /** escape character */
+ char ESCAPE_CHAR = '/';
+
+ /**
+ * Returns the policy id in the format used in the storage
+ * backend. Capital letters and forward slashes are escaped with
+ * a forward slash.
+ *
+ * @param aPolicyId id of policy requested by client
+ * @return id as stored in the backend
+ */
+ public String getStoredFormat(String aPolicyId) {
+ if (aPolicyId == null) { return null; }
+ String returnStr =
+ (String)policyIds.get(aPolicyId);
+ if (returnStr != null) { return returnStr; }
+ compBuf.delete(0, compBuf.length());
+ String allLowerCase = aPolicyId.toLowerCase();
+ char [] policyIdArray = aPolicyId.toCharArray();
+ char [] allLowerCaseArray = allLowerCase.toCharArray();
+ for (int i = 0; i < policyIdArray.length; ++i) {
+ if (policyIdArray[i] == ESCAPE_CHAR ||
+ policyIdArray[i] != allLowerCaseArray[i]) {
+ compBuf.append(ESCAPE_CHAR);
+ }
+ compBuf.append(policyIdArray[i]);
+ }
+ returnStr = compBuf.toString();
+ policyIds.put(aPolicyId, returnStr);
+ return returnStr;
+ }
+
+ /**
+ * Returns the policy id in the output format.
+ * Forward slashes are removed, and capital letters
+ * substituted as appropriate.
+ *
+ * @param aStoredPolicyId policy id in storage format
+ * @return policy id in output format
+ */
+ public String getOutputFormat(String aStoredPolicyId) {
+ if (aStoredPolicyId == null) { return null; }
+ compBuf.delete(0, compBuf.length());
+ char [] storedPolicyIdArray =
+ aStoredPolicyId.toCharArray();
+ String allUpperCase = aStoredPolicyId.toUpperCase();
+ char [] allUpperCaseArray = allUpperCase.toCharArray();
+ for (int i = 0; i < storedPolicyIdArray.length; ++i) {
+ if (storedPolicyIdArray[i] == ESCAPE_CHAR) {
+ compBuf.append(allUpperCaseArray[++i]);
+ } else {
+ compBuf.append(storedPolicyIdArray[i]);
+ }
+ }
+ String returnStr = compBuf.toString();
+ policyIds.put(returnStr, aStoredPolicyId);
+ return returnStr;
+ }
+ }
+
+}
+
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapDomain.java b/src/com/sun/apoc/spi/ldap/entities/LdapDomain.java
new file mode 100644
index 0000000..3bac976
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapDomain.java
@@ -0,0 +1,798 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPException;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.InvalidFilterException;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.util.BooleanReturnValue;
+
+/**
+ * Class for an LDAP domain entity.
+ *
+ */
+public class LdapDomain extends LdapNode
+ implements Domain
+{
+ private LdapDomain mParent;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId id entry for the host
+ * @param aParentIndex index for parent entity within id
+ * @param aDataStore datastore object
+ * @param aEntityMapping mapping object
+ * @param aContext client context
+ */
+ public LdapDomain (String aId, int aParentIndex, LdapDataStore aDataStore,
+ LdapEntityMapping aEntityMapping, LdapClientContext aContext) {
+ super(aId, aParentIndex, aDataStore, aEntityMapping, aContext);
+ setIsDomainTree();
+ if (aId.startsWith(LdapEntity.DOMAIN_TREE_INDICATOR)) {
+ mLocation =
+ aId.substring(LdapEntity.DOMAIN_TREE_INDICATOR.length());
+ }
+ }
+
+ /**
+ * Tests for equality with another Entity.
+ *
+ * @param aEntity other entity
+ * @return <code>true</code> if both entities are
+ * equal, otherwise <code>false</code>
+ */
+ public boolean equals (Object aEntity) {
+ if (aEntity instanceof LdapDomain) {
+ return LDAPDN.equals(mLocation.toLowerCase(),
+ ((LdapDomain) aEntity).mLocation.toLowerCase()) ;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the child domains, roles and hosts.
+ *
+ * @return <code>Iterator</code> of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getChildren() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ return getChildren(LdapEntity.NOT_CHECK_ONLY, returnValue);
+ }
+
+ /**
+ * Returns the child domains, roles and hosts.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are children, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return <code>Iterator</code> of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getChildren(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector allChildren = getAllChildrenList(aCheckOnly, aReturnValue);
+ return allChildren.iterator();
+ }
+
+ /**
+ * Returns the child domains, roles and hosts.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are children, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return array of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getChildrenArray(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector allChildren = getAllChildrenList(aCheckOnly, aReturnValue);
+ Entity[] entities = new Entity[allChildren.size()];
+ for (int i = 0; i < allChildren.size(); ++i) {
+ entities[i] = (Entity)allChildren.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns the list child domains, roles and hosts.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are children, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return <code>Vector</code> of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector getAllChildrenList(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector allChildren = new Vector();
+ String container = null;
+ String searchFilter = buildClassFilter(mEntityMapping.mDomainMapping,
+ false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.DOMAIN, container, aCheckOnly, aReturnValue);
+ if (aCheckOnly && aReturnValue.getReturnValue()) { return allChildren; }
+ allChildren.addAll(childrenList);
+ /*
+ // Commented out because there should be any role in the domain tree
+ searchFilter = buildClassFilter(mEntityMapping.mRoleMapping,
+ false);
+ childrenList = getChildrenList (searchFilter,
+ LdapEntityType.ROLE, container, aCheckOnly, aReturnValue);
+ if (aCheckOnly && aReturnValue.getReturnValue()) { return allChildren; }
+ allChildren.addAll(childrenList);
+ */
+ searchFilter = buildClassFilter(mEntityMapping.mHostMapping,
+ false);
+ container = mEntityMapping.mHostMapping.getContainerEntry();
+ childrenList = getChildrenList (searchFilter,
+ LdapEntityType.HOST, container, aCheckOnly, aReturnValue);
+ if (aCheckOnly && aReturnValue.getReturnValue()) { return allChildren; }
+ if (childrenList!=null) {
+ allChildren.addAll(childrenList);
+ }
+ return allChildren;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has children.
+ *
+ * @return <code>true</code> if there are children, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasChildren() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ getChildren(LdapEntity.CHECK_ONLY, returnValue);
+ return returnValue.getReturnValue();
+ }
+
+ /**
+ * Returns the child domains, roles and hosts.
+ *
+ * @return array of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getChildrenArray() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ return getChildrenArray(LdapEntity.NOT_CHECK_ONLY, returnValue);
+ }
+
+ /**
+ * Returns the subdomains.
+ *
+ * @return <code>Iterator</code> of child domains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getSubDomains () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(mEntityMapping.mDomainMapping,
+ false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.DOMAIN, null, false, returnValue);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the subdomains.
+ *
+ * @return array of subdomains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getSubDomainsArray () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(mEntityMapping.mDomainMapping,
+ false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.DOMAIN, null, false, returnValue);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+ /**
+ * Finds the domains that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child domains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findSubDomainsByName (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubDomainsByNameList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the subdomains that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of subdomains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findSubDomainsByNameArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubDomainsByNameList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+ /**
+ * Finds the subdomains that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child domains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findSubDomainsByFilter (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubDomainsByFilterList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the subdomains that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of subdomains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findSubDomainsByFilterArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubDomainsByFilterList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Finds the hosts that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findHostsByName (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findHostsByNameList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the hosts that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findHostsByNameArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findHostsByNameList(aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+ /**
+ * Finds the hosts that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findHostsByFilter (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findHostsByFilterList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the hosts that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findHostsByFilterArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findHostsByFilterList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+
+ /**
+ * Returns the child hosts.
+ *
+ * @return <code>Iterator</code> of child hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getHosts () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mHostMapping, false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.HOST, mEntityMapping.mHostMapping.getContainerEntry(),
+ false, returnValue);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the child hosts.
+ *
+ * @return array of child hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getHostsArray () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mHostMapping, false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.HOST, mEntityMapping.mHostMapping.getContainerEntry(),
+ false, returnValue);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns the parent domain.
+ *
+ * @return parent domain
+ */
+ public Entity getParent() {
+ if (mParent == null && mParentIndex != -1) {
+ String [] elements = LDAPDN.explodeDN(mLocation, false) ;
+ if (mParentIndex >= elements.length) { return null; }
+ StringBuffer dn = new StringBuffer(elements [mParentIndex]) ;
+ for (int i = mParentIndex + 1 ; i < elements.length ; ++ i) {
+ dn.append(LDAP_SEPARATOR).append(elements [i]) ;
+ }
+ mParent= (LdapDomain)getEntityFromDN(dn.toString(), LdapEntityType.DOMAIN, false,
+ null);
+ }
+ return mParent;
+ }
+ /**
+ * Returns domains that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for domains
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of domain objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Iterator findSubDomains(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findSubDomainsByFilter(aFilter, aIsRecursive);
+ } else {
+ return findSubDomainsByName(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Returns domains that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for domains
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of domains objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Entity[] findSubDomainsArray(String aFilter, boolean aIsRecursive)
+ throws SPIException{
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findSubDomainsByFilterArray(aFilter, aIsRecursive);
+ } else {
+ return findSubDomainsByNameArray(aFilter, aIsRecursive);
+ }
+ }
+
+
+ /**
+ * Finds the entities within this domain that match the
+ * specified filter. The entities can be domains, roles, or
+ * hosts.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findEntitiesByNameList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector allEntities = findHostsByNameList(aFilter, aIsRecursive);
+ Vector domainEntities = findSubDomainsByNameList(aFilter, aIsRecursive);
+ for (int i = 0; i < domainEntities.size(); ++i) {
+ allEntities.add(domainEntities.get(i));
+ }
+ Vector roleEntities = findRolesByNameList(aFilter, aIsRecursive);
+ for (int i = 0; i < roleEntities.size(); ++i) {
+ allEntities.add(roleEntities.get(i));
+ }
+ return allEntities;
+ }
+ /**
+ * Finds the domains within this domain that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child domains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findSubDomainsByNameList(String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ String nameFilter = buildNameFilter(aFilter, "=",
+ mEntityMapping.mDomainMapping, aIsRecursive);
+ Vector subEntities = searchForDomains(nameFilter, aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Returns hosts that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for hosts
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of hosts objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Iterator findHosts(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findHostsByFilter(aFilter, aIsRecursive);
+ } else {
+ return findHostsByName(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Returns hosts that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for hosts
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of hosts objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Entity[] findHostsArray(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findHostsByFilterArray(aFilter, aIsRecursive);
+ } else {
+ return findHostsByNameArray(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Finds the hosts within this domain that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findHostsByNameList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ String nameFilter = buildNameFilter(aFilter, "=",
+ mEntityMapping.mHostMapping, aIsRecursive);
+ Vector subEntities = searchForHosts(nameFilter,aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Finds the entities within this domain that match the
+ * specified filter. The entities can be domains, roles, or
+ * hosts.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findEntitiesByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector allEntities = findHostsByFilterList(aFilter, aIsRecursive);
+ Vector domainEntities = findSubDomainsByFilterList(aFilter, aIsRecursive);
+ for (int i = 0; i < domainEntities.size(); ++i) {
+ allEntities.add(domainEntities.get(i));
+ }
+ Vector roleEntities = findRolesByFilterList(aFilter, aIsRecursive);
+ for (int i = 0; i < roleEntities.size(); ++i) {
+ allEntities.add(roleEntities.get(i));
+ }
+ return allEntities;
+ }
+
+ /**
+ * Finds the subdomains within this domain that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child domains
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findSubDomainsByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ String mapFilter = mapFilter(aFilter,
+ mEntityMapping.mDomainMapping, aIsRecursive);
+ Vector subEntities = searchForDomains(mapFilter, aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Finds the hosts within this domain that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child hosts
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findHostsByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ String mapFilter = mapFilter(aFilter,
+ mEntityMapping.mHostMapping, aIsRecursive);
+ Vector subEntities = searchForHosts(mapFilter, aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Returns domain entities whose attributes match
+ * a given LDAP filter.
+ *
+ * @param aFilter LDAP search filter
+ * @param aRecursive true if recursive search, false otherwise
+ * @return <code>Vector</code> of <code>Entity</code>s representing
+ * the matching domain entities
+ * @throws SPIException if error occurs
+ * @throws IllegalReadException if error occurs
+ */
+ private Vector searchForDomains(String aFilter,
+ boolean aRecursive) throws SPIException {
+ StringBuffer baseDnBuf = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ String []attributes = { LdapDataStore.LDAP_OBJCLASS};
+ Vector results = null;
+ try {
+ results = (getDataStore()).performSearch(mLocation,
+ aRecursive, aFilter,
+ attributes, LdapEntity.DN_REQUIRED,
+ LdapEntity.NOT_CHECK_ONLY,
+ null, false, getContext()) ;
+ } catch (IllegalReadException ire) {
+ if (LdapDataStore.getLdapErrorCode(ire)
+ == LDAPException.NO_SUCH_OBJECT) {
+ return new Vector();
+ }
+ throw ire;
+ }
+ // We have to ensure every result is actually mappable
+ // into a proper entity. What can happen is that we get
+ // entries that conform to the filter but that for instance
+ // are not stored under the proper container (role, or host)
+ // and so must be ignored by us.
+ Vector retCode = new Vector();
+ if (!results.isEmpty()) {
+ int size = results.size();
+ Entity tmpEntity = null;
+ for (int i = 0 ; i < size ; i++) {
+ try {
+ Hashtable attrsValues = (Hashtable)results.get(i);
+ Vector values =
+ (Vector)attrsValues.get(LdapDataStore.DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ tmpEntity = getEntityFromDN((String) values.get(0),
+ LdapEntityType.DOMAIN, false, attrsValues);
+ }
+ if (tmpEntity != null) {
+ /* if it is a recursive search then need
+ to exclude the start domain from the results */
+ boolean excludeThisEntity = aRecursive;
+ if (excludeThisEntity) {
+ if (!this.equals(tmpEntity)) {
+ retCode.add(tmpEntity) ;
+ } else {
+ // have excluded the start entity
+ excludeThisEntity = false;
+ }
+ } else {
+ retCode.add(tmpEntity) ;
+ }
+ }
+ } catch (Exception ignore) {
+ /* cannot convert DN to entity, so omit from list */
+ }
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns host entities whose attributes match
+ * a given LDAP filter.
+ *
+ * @param aFilter LDAP search filter
+ * @param aRecursive true if recursive search, false otherwise
+ * @return <code>Vector</code/> of <code>Entity</code>s representing
+ * the matching entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Vector searchForHosts(String aFilter,
+ boolean aRecursive) throws SPIException {
+ StringBuffer baseDnBuf = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ String [] attributes = new String[2];
+ attributes[0] = LdapEntityMapping.OBJCLASS;
+ attributes[1] =
+ mEntityMapping.mHostMapping.getUniqueAttribute();
+ if (!aRecursive) {
+ String container = mEntityMapping.mHostMapping.getContainerEntry();
+ if (container != null && container != "") {
+ baseDnBuf.append(container).append(LdapEntity.LDAP_SEPARATOR);
+ }
+ }
+ baseDnBuf.append(mLocation);
+ Vector results = null;
+ try {
+ results = getDataStore().performSearch(
+ baseDnBuf.toString(),
+ aRecursive, aFilter,
+ attributes, LdapEntity.DN_REQUIRED,
+ LdapEntity.NOT_CHECK_ONLY,
+ null, false, getContext()) ;
+ } catch (IllegalReadException ire) {
+ if (LdapDataStore.getLdapErrorCode(ire)
+ == LDAPException.NO_SUCH_OBJECT) {
+ return new Vector();
+ }
+ throw ire;
+ }
+ // We have to ensure every result is actually mappable
+ // into a proper entity. What can happen is that we get
+ // entries that conform to the filter but that for instance
+ // are not stored under the proper container
+ // and so must be ignored by us.
+ Vector retCode = new Vector();
+ if (!results.isEmpty()) {
+ int size = results.size();
+ Entity tmpEntity = null;
+ for (int i = 0 ; i < size ; i++) {
+ try {
+ Hashtable attrsValues = (Hashtable)results.get(i);
+ Vector values =
+ (Vector)attrsValues.get(LdapDataStore.DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ tmpEntity = getEntityFromDN((String) values.get(0),
+ LdapEntityType.HOST, false, attrsValues);
+ }
+ if (tmpEntity != null) {
+ retCode.add(tmpEntity);
+ }
+ } catch (Exception ignore) {
+ /* cannot convert DN to entity, so omit from list */
+ }
+ }
+ }
+ return retCode;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapDomainProvider.java b/src/com/sun/apoc/spi/ldap/entities/LdapDomainProvider.java
new file mode 100644
index 0000000..a7fd5f2
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapDomainProvider.java
@@ -0,0 +1,99 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.entities;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.AbstractEntity;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.DomainTreeProvider;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.ldap.LdapConnectionHandler;
+
+/**
+ * Provides access to a domain tree stored in a LDAP backend
+ *
+ */
+public class LdapDomainProvider
+ extends LdapEntityProvider implements DomainTreeProvider {
+ public LdapDomainProvider(PolicySource aPolicySource, String url)
+ throws SPIException {
+ super(aPolicySource, url);
+ }
+
+ /**
+ * Opens the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws OpenConnectionException if connection error occurs
+ * @throws CloseConnectionException if connection error occurs
+ * @throws AuthenticateException if connection error occurs
+ */
+ public void open() throws SPIException {
+ if ((mConnection == null) && (mEnvironmentMgr != null)) {
+ mConnection = new LdapConnectionHandler();
+ mConnection.connect(mURL,
+ mEnvironmentMgr.getDomainTimeout(),
+ mEnvironmentMgr.getDomainAuthUser(),
+ mEnvironmentMgr.getDomainAuthPassword(),
+ mEnvironmentMgr);
+ if (isGSSAPIAuthentication()){
+ Object callbackHandler =
+ mEnvironmentMgr.getDomainCallbackHandler();
+ mConnection.authenticate(callbackHandler);
+ }
+ else {
+ mConnection.authenticate(mEnvironmentMgr.getDomainUser(mURL),
+ mEnvironmentMgr.getDomainCredentials());
+ }
+ mConnection.closeAuthorizedContext();
+
+ // store the new LdapConnectionHandler in the PolicyManager
+ mPolicySource.setConnectionHandler(mURL, mConnection);
+ }
+ mDataStore = mConnection.getDataStore();
+ mRootNode = mDataStore.getRootDomain();
+ ((AbstractEntity)mRootNode).setPolicySource(mPolicySource);
+ }
+
+ protected boolean isGSSAPIAuthentication() {
+ return mEnvironmentMgr.getDomainAuthType()
+ .equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI);
+ }
+
+ public Domain getRootDomain() throws SPIException
+ {
+ return (Domain)super.getRootEntity();
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapEntity.java b/src/com/sun/apoc/spi/ldap/entities/LdapEntity.java
new file mode 100644
index 0000000..35ea59d
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapEntity.java
@@ -0,0 +1,524 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale;
+import java.util.Vector;
+
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPException;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.AbstractEntity;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+
+/**
+ * Class for an LDAP entity.
+ */
+public abstract class LdapEntity extends AbstractEntity
+{
+ public static final String DOMAIN_TREE_INDICATOR = "1__";
+ public static final boolean CHECK_ONLY = true;
+ public static final boolean NOT_CHECK_ONLY = false;
+ public static final boolean DN_REQUIRED = true;
+ public static final boolean DN_NOT_REQUIRED = false;
+ public static final String LDAP_SEPARATOR = ",";
+ public static final char DN_SEPARATOR = '=';
+
+ LdapDataStore mDataStore;
+ LdapClientContext mContext;
+ LdapEntityMapping mEntityMapping;
+ String mLocation;
+ int mParentIndex;
+ boolean mIsDomainTree;
+ protected String mDisplayName ;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId id entry for the user
+ * @param aParentIndex index for parent entity within id
+ * @param aDataStore datastore object
+ * @param aEntityMapping mapping object
+ * @param aContext client context
+ */
+ protected LdapEntity(String aId, int aParentIndex,
+ LdapDataStore aDataStore,
+ LdapEntityMapping aEntityMapping, LdapClientContext aContext) {
+ mId = aId;
+ mDataStore = aDataStore;
+ mContext = aContext;
+ mEntityMapping = aEntityMapping;
+ mParentIndex = aParentIndex;
+ mLocation = aId;
+ }
+
+ /**
+ * Returns the datastore used by this entity.
+ *
+ * @return the datastore object
+ */
+ public LdapDataStore getDataStore() {
+ return mDataStore;
+ }
+
+ /**
+ * Returns the context.
+ *
+ * @return the context object
+ */
+ public LdapClientContext getContext() {
+ return mContext;
+ }
+
+ /**
+ * Sets the context.
+ *
+ * @param aContext the context
+ */
+ public void setContext(LdapClientContext aContext) {
+ mContext = aContext;
+ }
+
+ /**
+ * Tests for equality with another LdapEntity.
+ *
+ * @param aEntity other entity
+ * @return <code>true</code> if both entities are
+ * equal, otherwise <code>false</code>
+ */
+ public abstract boolean equals (Object aEntity) ;
+
+
+ /**
+ * Returns the location for this entity.
+ *
+ * @return the location
+ */
+ public String getLocation() {
+ return mLocation;
+ }
+
+
+ /**
+ * Returns the display name for this entity.
+ *
+ * @return the display name
+ */
+ public String getDisplayName(Locale aLocale) {
+ if (mDisplayName == null) {
+ try {
+ if (this.equals(mPolicySource.getRoot())) {
+ mDisplayName = mLocation;
+ }
+ } catch (SPIException ignore) {}
+ if (mDisplayName == null) {
+ mDisplayName = getDisplayNameFromLocation();
+ }
+ }
+ return mDisplayName;
+ }
+
+ /**
+ * Returns an interator over the display names of the ancestors
+ * of this entity, starting from the root entity down to the direct
+ * parent of this entity, reflecting the entity structure.
+ *
+ * The User and Host containers need to be skipped because they're
+ * not real entities.
+ *
+ * The ancestor name for the root is the full DN while for the other
+ * entities it is only the right part of the '=' sign.
+ *
+ * @return display names of the ancestors
+ */
+ public Iterator getAncestorNames(Locale aLocale) {
+ String userContainer = mEntityMapping.mUserMapping.getContainerEntry();
+ String hostContainer = mEntityMapping.mHostMapping.getContainerEntry();
+ String[] rootElements = null;
+ String rootOrgId = null;
+ try {
+ rootOrgId = mPolicySource.getRoot().getId();
+ rootElements = LDAPDN.explodeDN(rootOrgId, false);
+ } catch (SPIException ignore) {};
+ String[] elements = LDAPDN.explodeDN(mLocation, false);
+ LinkedList ancestorNames = new LinkedList();
+ if (elements != null) {
+ int lastElement = elements.length-1;
+ if (rootElements != null) {
+ lastElement = elements.length-rootElements.length-1;
+ if (elements.length > rootElements.length) {
+ // the current entity isn't a root entity
+ // so add root id as first ancestor
+ ancestorNames.add(LDAPDN.unEscapeRDN(rootOrgId));
+ }
+ }
+ for (int i=lastElement; i>0; i--) {
+ String ancestor = elements [i];
+ if (!ancestor.equals(userContainer) && !ancestor.equals(hostContainer)) {
+ int index = ancestor.indexOf(DN_SEPARATOR);
+ if (index >= 0) {
+ ancestorNames.add(LDAPDN.unEscapeRDN(ancestor.substring(index+1)));
+ }
+ }
+ }
+ }
+ return ancestorNames.iterator();
+ }
+
+ /**
+ * Returns parent entity.
+ *
+ * @return parent entity
+ */
+ public abstract Entity getParent() ;
+
+ /**
+ * Computes a default value for the display name from the id.
+ */
+ private String getDisplayNameFromLocation() {
+ String displayName = null;
+ String elements [] = LDAPDN.explodeDN(mLocation, true) ;
+ if ((elements != null) && (elements.length > 0)) {
+ displayName = LDAPDN.unEscapeRDN(elements [0]) ;
+ }
+ return displayName;
+ }
+
+ /**
+ * Returns a boolean indicating if this entity is in the domain tree.
+ *
+ * @return <code>true</code> is entity is in domain tree,
+ * otherwise <code>false</code>
+ */
+ public boolean isDomainTree() { return mIsDomainTree; }
+
+ /**
+ * Sets the boolean member and the id member to indicate
+ * this entity is in the domain tree.
+ *
+ */
+ protected void setIsDomainTree() {
+ mIsDomainTree = true;
+ }
+
+ /**
+ * Queries the necessary attributes to either do some guesswork on the
+ * type of an entity or to build the display name of fancy entries (such
+ * as users).
+ */
+ private Hashtable fillAttributeValues(String aDn) {
+ String []attributes = new String[2 +
+ mEntityMapping.mUserMapping.getDisplayAttributes().length];
+
+ attributes[0] = LdapDataStore.LDAP_OBJCLASS;
+ attributes[1] = mEntityMapping.mUserMapping.getUniqueAttribute();
+ int index = 2;
+ for (int i = 0; i <
+ mEntityMapping.mUserMapping.getDisplayAttributes().length; ++i) {
+ attributes[index++] = mEntityMapping.mUserMapping.getDisplayAttributes()[i];
+ }
+ try {
+ return getDataStore().getAttributeValueTable(
+ aDn, true, attributes, getContext());
+ } catch (LDAPException e) { return null; }
+ }
+ /**
+ * Builds an entity from a DN.
+ *
+ * @param aDN Distinguished Name
+ * @param aEntityType type of <code>Entity</code> to create
+ * @param aIncludesServiceElements <code>true</code> if this DN
+ * includes service elements
+ * @param aAttrsValues table of attribute/values mappings
+ * @return new entity or null if an error occurs.
+ */
+ public Entity getEntityFromDN(String aDN, LdapEntityType aEntityType,
+ boolean aIncludesServiceElements, Hashtable aAttrsValues) {
+ if (aDN == null) { return null ; }
+ String [] components = null ;
+ int start = 0 ;
+ String dn = aDN ;
+
+ if (aIncludesServiceElements) {
+ components = LDAPDN.explodeDN(aDN, false) ;
+ if (components == null) { return null ; }
+ start = LdapDataStore.NUMBER_OF_SERVICE_MAPPING_ELEMENTS ;
+ if (start >= components.length) { return null ; }
+ StringBuffer buffer = new StringBuffer(components [start]) ;
+ for (int i = start + 1 ; i < components.length ; ++ i) {
+ buffer.append(LDAP_SEPARATOR).append(components [i]) ;
+ }
+ dn = buffer.toString() ;
+ }
+ if (isDomainTree()) {
+ if ((((LdapEntity)getDataStore().getRootDomain()).getLocation().equalsIgnoreCase(dn))) {
+ return getDataStore().getRootDomain();
+ }
+ } else {
+ if ((((LdapEntity)getDataStore().getRootOrganization()).getLocation().equalsIgnoreCase(dn))) {
+ return getDataStore().getRootOrganization();
+ }
+ }
+ if (aEntityType == LdapEntityType.UNKNOWN) {
+ if (components == null) {
+ components = LDAPDN.explodeDN(aDN, false) ;
+ }
+ if (aAttrsValues == null) {
+ aAttrsValues = fillAttributeValues(dn) ;
+ if (aAttrsValues == null) { return null ; }
+ }
+ aEntityType = detectEntityType(components[start], aAttrsValues) ;
+ if (aEntityType == LdapEntityType.UNKNOWN) { return null ; }
+ if (!isCompatible(aEntityType)) { return null ; }
+ }
+ String container = null ;
+ int containerIndex = 1 ;
+ int entityType = aEntityType.getIntValue() ;
+ switch (entityType) {
+ case LdapEntityType.INT_USERID:
+ container = mEntityMapping.mUserMapping.getContainerEntry() ;
+ break ;
+ case LdapEntityType.INT_HOST:
+ container = mEntityMapping.mHostMapping.getContainerEntry() ;
+ break ;
+ case LdapEntityType.INT_ROLE:
+ container = mEntityMapping.mRoleMapping.getContainerEntry() ;
+ containerIndex = -1 ;
+ break ;
+ default:
+ containerIndex = 0 ;
+ break ;
+ }
+ if (container != null && container.length() == 0) { container = null ; }
+ if (containerIndex == -1) {
+ if (components == null) {
+ components = LDAPDN.explodeDN(aDN, false) ;
+ }
+ containerIndex = findContainer(components, start, container) ;
+ if (containerIndex == -1) { return null ; }
+ // deal with service elements
+ containerIndex -= start;
+ }
+ Entity retCode = null;
+ String uniqueIdAttr = null;
+ switch (entityType) {
+ case LdapEntityType.INT_ORG:
+ retCode = new LdapOrganization(dn, containerIndex + 1,
+ getDataStore(), mEntityMapping, getContext());
+ break;
+ case LdapEntityType.INT_DOMAIN:
+ retCode = new LdapDomain(dn, containerIndex + 1,
+ getDataStore(), mEntityMapping, getContext());
+ break;
+ case LdapEntityType.INT_ROLE:
+ retCode = new LdapRole(dn, containerIndex + 1,
+ getDataStore(), mEntityMapping, getContext());
+ if (isDomainTree()) {
+ ((LdapRole)retCode).setIsDomainTree();
+ }
+ break;
+ case LdapEntityType.INT_USERID:
+ retCode = new LdapUser(dn, containerIndex + 1,
+ getDataStore(), mEntityMapping, getContext());
+ if (aAttrsValues == null) {
+ aAttrsValues = fillAttributeValues(dn) ;
+ if (aAttrsValues == null) { return null ; }
+ }
+ ((LdapUser)retCode).setDisplayName(aAttrsValues,
+ mEntityMapping.mUserMapping.getDisplayAttributes(),
+ mEntityMapping.mUserMapping.getDisplayFormat()) ;
+ break;
+ case LdapEntityType.INT_HOST:
+ retCode = new LdapHost(dn, containerIndex + 1,
+ getDataStore(), mEntityMapping, getContext());
+ break;
+ }
+ if (retCode != null) {
+ ((AbstractEntity)retCode).setPolicySource(mPolicySource);
+ }
+ return retCode;
+ }
+
+ private boolean isCompatible(LdapEntityType aEntityType) {
+ if (mPolicySource.getName().equals(EnvironmentConstants.USER_SOURCE)) {
+ if (aEntityType.equals(LdapEntityType.DOMAIN) ||
+ aEntityType.equals(LdapEntityType.HOST)) {
+ return false;
+ } else {
+ return true;
+ }
+ } else if (mPolicySource.getName().equals(EnvironmentConstants.HOST_SOURCE)) {
+ if (aEntityType.equals(LdapEntityType.DOMAIN) ||
+ aEntityType.equals(LdapEntityType.HOST)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Finds the type of an entity by checking its objectclass.
+ *
+ * @param aRDN RDN of the object
+ * @param aAttrValues table containing entity objectclasses
+ * @return entity type
+ */
+ public LdapEntityType detectEntityType(String aRDN, Hashtable aAttrValues) {
+ LdapEntityType returnType = LdapEntityType.UNKNOWN;
+ Vector objClasses =
+ (Vector)aAttrValues.get(LdapDataStore.LDAP_OBJCLASS);
+ if (objClasses == null || objClasses.isEmpty()) {
+ return returnType;
+ }
+ Enumeration classes = objClasses.elements();
+ ArrayList classList = new ArrayList();
+ while (classes.hasMoreElements()) {
+ classList.add(classes.nextElement());
+ }
+ int numOfClasses = classList.size();
+ int index = 0;
+ while (index < numOfClasses &&
+ returnType == LdapEntityType.UNKNOWN) {
+ String objClass = (String)classList.get(index);
+ if (objClass.equalsIgnoreCase(mEntityMapping.mUserMapping.getObjectClass())) {
+ returnType = LdapEntityType.USERID;
+ break;
+ } else if (objClass.equalsIgnoreCase(mEntityMapping.mHostMapping.getObjectClass())) {
+ returnType = LdapEntityType.HOST;
+ break;
+ } else {
+ String orgObjClasses[] =
+ mEntityMapping.mOrganizationMapping.getObjectClasses();
+ for (int i = 0; i < orgObjClasses.length; ++i) {
+ if (objClass.equalsIgnoreCase(
+ orgObjClasses[i])) {
+ returnType = LdapEntityType.ORG;
+ break;
+ }
+ }
+ if (returnType == LdapEntityType.UNKNOWN) {
+ String roleObjClasses[] =
+ mEntityMapping.mRoleMapping.getObjectClasses();
+ for (int i = 0; i < roleObjClasses.length; ++i) {
+ if (objClass.equalsIgnoreCase(
+ roleObjClasses[i])) {
+ returnType = LdapEntityType.ROLE;
+ break;
+ }
+ }
+ }
+ if (returnType == LdapEntityType.UNKNOWN) {
+ String domainObjClasses[] =
+ mEntityMapping.mDomainMapping.getObjectClasses();
+ for (int i = 0; i < domainObjClasses.length; ++i) {
+ if (objClass.equalsIgnoreCase(
+ domainObjClasses[i])) {
+ returnType = LdapEntityType.DOMAIN;
+ break;
+ }
+ }
+ }
+ }
+ ++index;
+ }
+ if (returnType == LdapEntityType.USERID) {
+ // ensure not a host (for Active Directory)
+ for (int i = 0; i < numOfClasses; ++i) {
+ String objClass = (String)classList.get(i);
+ if (objClass.equalsIgnoreCase(
+ mEntityMapping.mHostMapping.getObjectClass())) {
+ returnType = LdapEntityType.HOST;
+ break;
+ }
+ }
+ }
+ return returnType;
+ }
+
+
+ /**
+ * Returns the index of the container entry in a DN.
+ * If there should be a container and it cannot be found,
+ * or there shouldn't be but a real parent (org or domain)
+ * cannot be found either return -1.
+ *
+ * @param aComponents dn components
+ * @param aStart where to start looking in the components
+ * @param aContainer container entry or null if doesn't exist
+ * @return container index or -1 if erroneous situation
+ */
+ private static int findContainer(String [] aComponents,
+ int aStart, String aContainer) {
+ String beginning = aComponents [aStart].substring(0,
+ aComponents [aStart].indexOf("=")) ;
+ for (int i = aStart + 1 ; i < aComponents.length ; ++ i) {
+ if (aContainer != null) {
+ if (aContainer.equalsIgnoreCase(aComponents [i])) {
+ return i ;
+ }
+ } else if (!aComponents [i].startsWith(beginning)) {
+ return i - 1 ;
+ }
+ }
+ return -1 ;
+ }
+
+ /**
+ * Returns an iterator of profiles
+ * that contribute to this entity's configuration data.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public abstract Iterator getLayeredProfiles()
+ throws SPIException ;
+
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapEntityProvider.java b/src/com/sun/apoc/spi/ldap/entities/LdapEntityProvider.java
new file mode 100644
index 0000000..72f6227
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapEntityProvider.java
@@ -0,0 +1,111 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.entities;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.EntityTreeProvider;
+import com.sun.apoc.spi.entities.Node;
+import com.sun.apoc.spi.ldap.LdapConnectionHandler;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.environment.LdapEnvironmentMgr;
+/**
+ * Provides (abstract) access to an entity tree stored
+ * in a LDAP backend
+ *
+ */
+public abstract class LdapEntityProvider implements EntityTreeProvider {
+
+ protected Node mRootNode;
+ protected PolicySource mPolicySource;
+ protected LdapConnectionHandler mConnection;
+ protected LdapDataStore mDataStore;
+ protected LdapEnvironmentMgr mEnvironmentMgr;
+ protected String mURL;
+
+ public LdapEntityProvider(PolicySource aPolicySource, String url)
+ throws SPIException {
+ mPolicySource = aPolicySource;
+ mURL = url;
+ mEnvironmentMgr = new LdapEnvironmentMgr(mPolicySource.getEnvironment());
+ mConnection = (LdapConnectionHandler) mPolicySource.getConnectionHandler(mURL);
+ if (mConnection == null) {
+ // if mConnection is null, no Ldap connection has been
+ // established yet, the environment hasn't been checked
+ mEnvironmentMgr.checkEnvironment();
+ }
+ }
+
+ /**
+ * Closes the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws CloseConnectionException if connection error occurs
+ */
+ public void close() throws SPIException {
+ if (mPolicySource.getConnectionHandler(mURL) != null) {
+ mPolicySource.setConnectionHandler(mURL, null);
+ }
+ mConnection.disconnect();
+ }
+
+ /**
+ * Returns the root node of the Entity Tree
+ *
+ * @return root node
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Node getRootEntity() throws SPIException {
+ return mRootNode;
+ }
+
+ /**
+ * Returns the entity for this id in the Entity Tree
+ *
+ * @param id id string
+ * @return entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity(String id) throws SPIException {
+ Entity entity = null;
+ if (id.equals(mRootNode.getId())) {
+ entity = mRootNode;
+ }
+ else {
+ entity = mRootNode.getEntity(id);
+ }
+ return entity;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapEntityType.java b/src/com/sun/apoc/spi/ldap/entities/LdapEntityType.java
new file mode 100644
index 0000000..a7d4b4d
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapEntityType.java
@@ -0,0 +1,130 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+import com.sun.apoc.spi.util.StringRangeEnum;
+
+/**
+ * Class <code>LdapEntityType</code> is a StringRangeEnum for
+ * storing the possible values of entity-type.
+ *
+ */
+
+public class LdapEntityType extends StringRangeEnum {
+
+ /**
+ * The LdapEntityType String constants uniquely identify the type.
+ */
+ public static final String STR_NULL = "";
+ public static final String STR_UNKNOWN = "UNKNOWN";
+ public static final String STR_ALL = "ALL";
+ public static final String STR_ORG = "ORG";
+ public static final String STR_DOMAIN = "DOMAIN";
+ public static final String STR_ROLE = "ROLE";
+ public static final String STR_USERID = "USERID";
+ public static final String STR_HOST = "HOST";
+
+ public static final int INT_NULL = 0;
+ public static final int INT_UNKNOWN = 1;
+ public static final int INT_ALL = 2;
+ public static final int INT_ORG = 3;
+ public static final int INT_DOMAIN = 4;
+ public static final int INT_ROLE = 5;
+ public static final int INT_USERID = 6;
+ public static final int INT_HOST = 7;
+
+ public static final LdapEntityType NULL = new LdapEntityType(INT_NULL);
+ public static final LdapEntityType UNKNOWN = new LdapEntityType(INT_UNKNOWN);
+ public static final LdapEntityType ALL = new LdapEntityType(INT_ALL);
+ public static final LdapEntityType ORG = new LdapEntityType(INT_ORG);
+ public static final LdapEntityType DOMAIN = new LdapEntityType(INT_DOMAIN);
+ public static final LdapEntityType ROLE = new LdapEntityType(INT_ROLE);
+ public static final LdapEntityType USERID = new LdapEntityType(INT_USERID);
+ public static final LdapEntityType HOST = new LdapEntityType(INT_HOST);
+
+ private LdapEntityType(int n) {
+ super(n);
+ }
+
+ protected String[] getEnumStrings() {
+ return enumStrings;
+ }
+ protected LdapEntityType[] getEnums() {
+ return enums;
+ }
+
+ private static final String enumStrings[] = {
+ STR_NULL,
+ STR_UNKNOWN,
+ STR_ALL,
+ STR_ORG,
+ STR_DOMAIN,
+ STR_ROLE,
+ STR_USERID,
+ STR_HOST
+ };
+
+ private static final LdapEntityType enums[] = {
+ NULL,
+ UNKNOWN,
+ ALL,
+ ORG,
+ DOMAIN,
+ ROLE,
+ USERID,
+ HOST
+ };
+
+ /**
+ * Factory method for StringEnum instances.
+ */
+ public static LdapEntityType getEntityType(String eString) {
+ for (int i=0; i < enumStrings.length; i++)
+ if (eString.equals(enumStrings[i]))
+ return enums[i];
+
+ return null;
+ }
+
+ /**
+ * Factory method for StringEnum instances.
+ */
+ public static LdapEntityType getEntityType(int n) {
+ if (n >=0 && n < enums.length)
+ return enums[n];
+
+ return null;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapHost.java b/src/com/sun/apoc/spi/ldap/entities/LdapHost.java
new file mode 100644
index 0000000..10ccef9
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapHost.java
@@ -0,0 +1,183 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import netscape.ldap.LDAPDN;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Host;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+
+/**
+ * Class for an LDAP host entity.
+ *
+ */
+public class LdapHost extends LdapEntity implements Host
+{
+ private LdapDomain mParent;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId id entry for the user
+ * @param aParentIndex index for parent entity within id
+ * @param aDataStore datastore object
+ * @param aEntityMapping mapping object
+ * @param aContext client context
+ */
+ public LdapHost (String aId, int aParentIndex, LdapDataStore aDataStore,
+ LdapEntityMapping aEntityMapping, LdapClientContext aContext) {
+ super(aId, aParentIndex, aDataStore, aEntityMapping, aContext);
+ setIsDomainTree();
+ }
+
+ /**
+ * Tests for equality with another Entity.
+ *
+ * @param aEntity other entity
+ * @return <code>true</code> if both entities are
+ * equal, otherwise <code>false</code>
+ */
+ public boolean equals (Object aEntity) {
+ if (aEntity instanceof LdapHost) {
+ return LDAPDN.equals(mLocation.toLowerCase(),
+ ((LdapHost) aEntity).mLocation.toLowerCase()) ;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the parent domain entity.
+ *
+ * @return parent domain entity
+ */
+ public Entity getParent() {
+ if (mParent == null) {
+ String [] elements = LDAPDN.explodeDN(mLocation, false) ;
+ StringBuffer dn = new StringBuffer(elements [mParentIndex]) ;
+ for (int i = mParentIndex + 1 ; i < elements.length ; ++ i) {
+ dn.append(LDAP_SEPARATOR).append(elements [i]) ;
+ }
+
+ mParent = (LdapDomain) getEntityFromDN(dn.toString(),
+ LdapEntityType.DOMAIN,
+ false, null) ;
+ }
+ return mParent;
+ }
+
+ /**
+ * Return list of roles of which this host is a member.
+ *
+ * @return <code>Iterator</code> listing roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getMemberships() throws SPIException {
+ return getListOfRoles().iterator();
+ }
+
+ /**
+ * Return list of roles of which this host is a member.
+ *
+ * @return array listing roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getMembershipsArray() throws SPIException {
+ Vector roleList = getListOfRoles();
+ Entity[] entities = new Entity[roleList.size()];
+ for (int i = 0; i < entities.length; ++i) {
+ entities[i] = (Entity)roleList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns the roles of which this user is a member. Roles
+ * are found by reading the computed user attribute
+ *
+ * @return <code>Vector</code> of roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Vector getListOfRoles() throws SPIException {
+ Vector roleList = getDataStore().getListedRolesForEntity(this,
+ mEntityMapping.mRoleMapping.getListingAttribute(),
+ getContext());
+ Vector retCode = new Vector();
+ if (!roleList.isEmpty()) {
+ int size = roleList.size();
+ Entity tmpEntity = null;
+ for (int i = 0; i < size; i++) {
+ try {
+ /* read the entry for this role in order
+ to obtain corret display name for Entity */
+ String dn = getDataStore().readEntryDN(
+ (String)roleList.get(i), getContext());
+ tmpEntity = getEntityFromDN((String)roleList.get(i),
+ LdapEntityType.ROLE, false, null);
+ if (tmpEntity != null) {
+ retCode.add(tmpEntity);
+ }
+ } catch (SPIException ignore) {
+ /* problem converting this DN, so omit it */
+ }
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns an iterator of profiles
+ * that contribute to this entity's configuration data.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public Iterator getLayeredProfiles()
+ throws SPIException {
+ Iterator parents = getAllParents();
+ Iterator roles = getMemberships();
+ return getLayeredProfiles(parents, roles);
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapNode.java b/src/com/sun/apoc/spi/ldap/entities/LdapNode.java
new file mode 100644
index 0000000..3c3d8f8
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapNode.java
@@ -0,0 +1,1283 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import netscape.ldap.LDAPException;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Node;
+import com.sun.apoc.spi.entities.InvalidFilterException;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.util.BooleanReturnValue;
+
+/**
+ * Abstract class for an LDAP entity container.
+ */
+public abstract class LdapNode extends LdapEntity
+ implements Node
+{
+ public static final String MODULE = "LdapNode";
+
+ public static final String SEARCH_FILTER_DELIMITER = "(";
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId id entry for the user
+ * @param aParentIndex index for parent entity within id
+ * @param aDataStore datastore object
+ * @param aEntityMapping mapping object
+ * @param aContext client context
+ */
+ public LdapNode (String aId, int aParentIndex,
+ LdapDataStore aDataStore, LdapEntityMapping aEntityMapping,
+ LdapClientContext aContext) {
+ super(aId, aParentIndex, aDataStore, aEntityMapping, aContext);
+ }
+
+
+ /**
+ * Returns a list of children of the specified type.
+ *
+ * @param aSearchFilter filter for search
+ * @param aChildType type of child required
+ * @param aContainer name of container for children
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are children of the specified
+ * type, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children
+ * of the specified type to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return <code>Vector</code> of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector getChildrenList (String aSearchFilter, LdapEntityType aChildType,
+ String aContainer, boolean aCheckOnly,
+ BooleanReturnValue aReturnValue)
+ throws SPIException {
+ Vector childrenList = null;
+ String []attributes = null;
+ switch (aChildType.getIntValue()) {
+ case LdapEntityType.INT_USERID:
+ attributes =
+ new String[2 + mEntityMapping.mUserMapping.getDisplayAttributes().length];
+ attributes[0] = LdapDataStore.LDAP_OBJCLASS;
+ attributes[1] =
+ mEntityMapping.mUserMapping.getUniqueAttribute();
+ int index = 2;
+ for (int i = 0; i <
+ mEntityMapping.mUserMapping.getDisplayAttributes().length; ++i) {
+ attributes[index++] =
+ mEntityMapping.mUserMapping.getDisplayAttributes()[i];
+ }
+ break;
+ case LdapEntityType.INT_HOST:
+ attributes = new String[2];
+ attributes[0] = LdapEntityMapping.OBJCLASS;
+ attributes[1] =
+ mEntityMapping.mHostMapping.getUniqueAttribute();
+ break;
+ default:
+ attributes = new String[1];
+ attributes[0] = LdapEntityMapping.OBJCLASS;
+ }
+ try {
+ childrenList = getDataStore().getListOfChildren(
+ this, aContainer,
+ aSearchFilter, LdapDataStore.NON_RECURSIVE_SEARCH, attributes,
+ aCheckOnly, getContext(), aReturnValue);
+ } catch (SPIException spie) {
+ int error = LdapDataStore.getLdapErrorCode(spie);
+ if ( (error != LDAPException.NO_RESULTS_RETURNED)
+ && (error != LDAPException.NO_SUCH_ATTRIBUTE)
+ && (error != LDAPException.NO_SUCH_OBJECT) ) {
+ throw spie;
+ }
+ }
+ if (aCheckOnly) { return childrenList ; }
+ Vector retCode = new Vector();
+ if (childrenList != null && !childrenList.isEmpty()) {
+ int size = childrenList.size();
+ Entity tmpEntity = null;
+ for (int i = 0; i < size; i++) {
+ try {
+ Hashtable attrsValues = (Hashtable)childrenList.get(i);
+ Vector values = (Vector)attrsValues.get(LdapDataStore.DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ String dN = (String)values.get(0);
+ tmpEntity = getEntityFromDN(dN, aChildType,
+ false, attrsValues);
+ if (tmpEntity != null) {
+ retCode.add(tmpEntity);
+ }
+ }
+ } catch (Exception ignore) {
+ /* problem converting this DN, so omit it */
+ }
+ }
+ }
+ return retCode == null ? new Vector() : retCode;
+ }
+
+ /**
+ * Returns contained entities that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for entities
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of entity objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Iterator findEntities(String aFilter, boolean aIsRecursive) throws SPIException {
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findEntitiesByFilter(aFilter, aIsRecursive);
+ } else {
+ return findEntitiesByName(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Returns contained entities that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for entities
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of entity objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Entity[] findEntitiesArray(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findEntitiesByFilterArray(aFilter, aIsRecursive);
+ } else {
+ return findEntitiesByNameArray(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Returns contained entities that match the specified name.
+ *
+ * @param aFilter the filter to use in searching for entities
+ * @param aIsRecursive <code>true</code> if recursive search, otherwise
+ * <code>false</code>
+ * @return <code>Iterator</code> of entity objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findEntitiesByName(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector entities = findEntitiesByNameList(aFilter, aIsRecursive);
+ return entities.iterator();
+ }
+
+ /**
+ * Finds the entities within this organization that match the
+ * specified filter. The entities can be organizations, roles, or
+ * users.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findEntitiesByNameArray(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector entities = findEntitiesByNameList(aFilter, aIsRecursive);
+ int size = entities.size();
+ Entity []entitiesArray = new Entity[size];
+ for (int i = 0; i < size; ++i) {
+ entitiesArray[i] = (Entity)entities.get(i);
+ }
+ return entitiesArray;
+ }
+
+ /**
+ * Finds the roles within this container that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findRolesByNameList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector subEntities =
+ subEntities = searchForRoles(
+ buildNameFilter(aFilter, "=",
+ mEntityMapping.mRoleMapping, aIsRecursive),
+ aIsRecursive);
+ return subEntities;
+ }
+ /**
+ * Finds the roles within this container that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findRolesByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector subEntities = searchForRoles(
+ mapFilter(aFilter,
+ mEntityMapping.mRoleMapping, aIsRecursive),
+ aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Returns contained entities that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for entities
+ * @param aIsRecursive <code>true</code> if recursive search, otherwise
+ * <code>false</code>
+ * @return <code>Iterator</code> of entity objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findEntitiesByFilter(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector entities = findEntitiesByFilterList(aFilter, aIsRecursive);
+ return entities.iterator();
+ }
+
+ /**
+ * Finds the entities within this organization that match the
+ * specified filter. The entities can be organizations, roles, or
+ * users.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findEntitiesByFilterArray(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector entities = findEntitiesByFilterList(aFilter, aIsRecursive);
+ int size = entities.size();
+ Entity []entitiesArray = new Entity[size];
+ for (int i = 0; i < size; ++i) {
+ entitiesArray[i] = (Entity)entities.get(i);
+ }
+ return entitiesArray;
+ }
+
+ /**
+ * Finds the entities within this container entity that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Vector findEntitiesByNameList(String aFilter,
+ boolean aIsRecursive) throws SPIException ;
+
+ /**
+ * Finds the entities within this container entity that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Vector findEntitiesByFilterList(String aFilter,
+ boolean aIsRecursive) throws SPIException ;
+ /**
+ * Returns roles that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for roles
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of roles objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Iterator findRoles(String aFilter, boolean aIsRecursive)
+ throws SPIException{
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findRolesByFilter(aFilter, aIsRecursive);
+ } else {
+ return findRolesByName(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Returns roles that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for roles
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of role objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Entity[] findRolesArray(String aFilter,
+ boolean aIsRecursive) throws SPIException{
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findRolesByFilterArray(aFilter, aIsRecursive);
+ } else {
+ return findRolesByNameArray(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Finds the roles that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findRolesByFilter (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findRolesByFilterList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the roles that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findRolesByFilterArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findRolesByFilterList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Finds the roles that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findRolesByName (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findRolesByNameList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+
+ /**
+ * Returns the roles that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findRolesByNameArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findRolesByNameList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns the entity for this id. Entity could be an organization,
+ * a role, or a user.
+ *
+ * @param aId id string
+ * @return entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity(String aId) throws SPIException {
+ return getEntityFromDN(aId, LdapEntityType.UNKNOWN, false, null);
+ }
+
+ /**
+ * Returns child entities.
+ *
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Iterator getChildren() throws SPIException;
+
+ /**
+ * Returns child entities.
+ *
+ * @return array of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Entity[] getChildrenArray() throws SPIException;
+
+ /**
+ * Returns leaf entities.
+ *
+ * @return <code>Iterator</code> of leaf entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getLeaves() throws SPIException {
+ return null;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has leaves.
+ *
+ * @return <code>true</code> if there are leaves, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasLeaves() throws SPIException {
+ return false;
+ }
+
+ /**
+ * Returns node entities.
+ *
+ * @return <code>Iterator</code> of node entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getNodes() throws SPIException {
+ return null;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has nodes.
+ *
+ * @return <code>true</code> if there are nodes, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasNodes() throws SPIException {
+ return false;
+ }
+
+ /**
+ * Returns the class filter for a container entity, i.e. the
+ * union of all possible objectclasses.
+ *
+ * @param aContainerMapping container mapping object
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * other wise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if the type is invalid.
+ */
+ public String buildClassFilter(
+ LdapEntityMapping.ContainerMapping aContainerMapping,
+ boolean aIsRecursive) throws SPIException {
+ StringBuffer retCode = buildClassFilterString(aContainerMapping.getObjectClasses(),
+ aIsRecursive);
+ if (aContainerMapping instanceof LdapEntityMapping.ListMapping) {
+ addRoleFilterPlus(aIsRecursive, retCode);
+ }
+ return retCode.toString() ;
+ }
+
+ /**
+ * Returns the class filter for a user.
+ *
+ * @param aUserMapping mapping for user
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if the type is invalid.
+ */
+ public String buildClassFilter(
+ LdapEntityMapping.UserMapping aUserMapping,
+ boolean aIsRecursive) throws SPIException {
+ String []objectClass = {aUserMapping.getObjectClass()};
+ StringBuffer retCode = buildClassFilterString(objectClass,
+ aIsRecursive);
+ //exclude hosts from search (for Active Directory)
+ retCode.insert(0, "(&(!(" + LdapDataStore.LDAP_OBJCLASS + "="
+ + mEntityMapping.mHostMapping.getObjectClass() +
+ "))");
+ retCode.append(")");
+ return retCode.toString();
+ }
+
+ /**
+ * Returns the class filter for a host.
+ *
+ * @param aHostMapping mapping for host
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if the type is invalid.
+ */
+ public String buildClassFilter(
+ LdapEntityMapping.ItemMapping aHostMapping,
+ boolean aIsRecursive) throws SPIException {
+ String []objectClass = {aHostMapping.getObjectClass()};
+ StringBuffer retCode = buildClassFilterString(objectClass,
+ aIsRecursive);
+ return retCode.toString();
+ }
+
+ /**
+ * Returns the class filter string.
+ *
+ * @param aObjectClasses object classes
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private StringBuffer buildClassFilterString(String[] aObjectClasses,
+ boolean aIsRecursive) throws SPIException {
+ Vector subConditions = new Vector() ;
+ StringBuffer retCode = new StringBuffer() ;
+ boolean addExclusionFilter = false;
+ for (int i = 0 ; i < aObjectClasses.length ; ++ i) {
+ subConditions.add("(" + LdapDataStore.LDAP_OBJCLASS + "="
+ + aObjectClasses [i] + ")") ;
+ if (aObjectClasses[i].equalsIgnoreCase(LdapDataStore.ORG_UNIT_OBJCLASS)) {
+ addExclusionFilter = true; }
+ }
+ if (subConditions.size() > 1) {
+ retCode.append("(|") ;
+ int size = subConditions.size();
+ for (int i = 0 ; i < size ; ++ i) {
+ retCode.append(subConditions.get(i)) ;
+ }
+ retCode.append(")") ;
+ } else { retCode.append(subConditions.get(0)) ; }
+ if (addExclusionFilter) {
+ excludeServiceEntriesFromSearchFilter(aIsRecursive, retCode);
+ }
+ return retCode ;
+ }
+
+ /**
+ * Maps a filter to use the corresponding LDAP attributes.
+ *
+ * @param aFilter search filter
+ * @param aContainerMapping container mapping object
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if the type is invalid.
+ */
+ public String mapFilter(String aFilter,
+ LdapEntityMapping.ContainerMapping aContainerMapping,
+ boolean aIsRecursive) throws SPIException {
+ String classFilter = buildClassFilter(aContainerMapping, aIsRecursive) ;
+ if (aFilter == null || aFilter.length() == 0) {
+ return classFilter ;
+ }
+ StringBuffer retCode = new StringBuffer() ;
+ retCode.append("(&").append(classFilter) ;
+ retCode.append(buildMappedFilter(aFilter, aContainerMapping));
+ retCode.append(")") ;
+ return retCode.toString() ;
+ }
+
+ /**
+ * Returns the mapping of a filter from the SO attributes to
+ * the LDAP attributes.
+ * It is assumed that the type and filter are non-null and valid.
+ *
+ * @param aFilter filter to map
+ * @param aContainerMapping container mapping object
+ * @return mapped filter
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public String buildMappedFilter(String aFilter,
+ LdapEntityMapping.ContainerMapping aContainerMapping)
+ throws SPIException {
+ int lastChar = 0;
+ boolean hasExtraParentheses = false;
+ if (aFilter.charAt(0) == '(') {
+ lastChar = 1;
+ hasExtraParentheses = true;
+ }
+ ParsedAttribute attribute = new ParsedAttribute() ;
+ int currentChar = parseNextAttribute(aFilter, lastChar,
+ attribute) ;
+ StringBuffer tmpBuffer = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ Vector subConditions = new Vector();
+ while (currentChar != -1) {
+ tmpBuffer.delete(0, tmpBuffer.length());
+ String []attributes =
+ aContainerMapping.getNamingAttributes();
+ for (int i = 0; i < attributes.length; ++i) {
+ tmpBuffer.append("(");
+ tmpBuffer.append(attributes[i]);
+ tmpBuffer.append(attribute.mOperator).append(
+ attribute.mValue) ;
+ tmpBuffer.append(")");
+ }
+ subConditions.add(tmpBuffer.toString());
+ lastChar = attribute.mLastChar ;
+ currentChar = parseNextAttribute(aFilter, lastChar,
+ attribute) ;
+ }
+ StringBuffer retCode = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ if (subConditions.size() > 1) {
+ retCode.append("(&") ;
+ int size = subConditions.size();
+ for (int i = 0 ; i < size ; ++ i) {
+ retCode.append(subConditions.get(i)) ;
+ }
+ retCode.append(")") ;
+ } else { retCode.append(subConditions.get(0)) ; }
+ return retCode.toString() ;
+ }
+
+ /**
+ * Builds an LDAP boolean condition involving the naming
+ * attribute of a container entity.
+ * Since container entities are allowed to have multiple objectclasses
+ * and corresponding naming attributes, we have to build a
+ * filter representing the union of these possible cases.
+ *
+ * @param aPattern pattern that the attribute must match
+ * @param aOperator LDAP operator to be used for attribute matching
+ * @param aContainerMapping container mapping object
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String buildNameFilter(String aPattern, String aOperator,
+ LdapEntityMapping.ContainerMapping aContainerMapping,
+ boolean aIsRecursive) throws SPIException {
+ StringBuffer retCode = buildNameFilterString(aPattern, aOperator,
+ aContainerMapping.getObjectClasses(),
+ aContainerMapping.getNamingAttributes(),
+ aIsRecursive);
+ return retCode.toString() ;
+ }
+
+ /**
+ * Builds an LDAP boolean condition involving the naming
+ * attribute of role entity.
+ * Since role entities are allowed to have multiple objectclasses
+ * and corresponding naming attributes, we have to build a
+ * filter representing the union of these possible cases.
+ *
+ * @param aPattern pattern that the attribute must match
+ * @param aOperator LDAP operator to be used for attribute matching
+ * @param aListMapping list mapping object
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String buildNameFilter(String aPattern, String aOperator,
+ LdapEntityMapping.ListMapping aRoleMapping,
+ boolean aIsRecursive) throws SPIException {
+ StringBuffer retCode = buildNameFilterString(
+ aPattern, aOperator, aRoleMapping.getObjectClasses(),
+ aRoleMapping.getNamingAttributes(),
+ aIsRecursive);
+ addRoleFilterPlus(aIsRecursive, retCode);
+ return retCode.toString();
+ }
+
+ /**
+ * Builds an LDAP boolean condition involving the naming
+ * attributes of an entity.
+ * Since container entities are allowed to have multiple objectclasses
+ * and corresponding naming attributes, we have to build a
+ * filter representing the union of these possible cases.
+ *
+ * @param aPattern pattern that the attribute must match
+ * @param aOperator LDAP operator to be used for attribute matching
+ * @param aObjectClasses object classes
+ * @param aNamingAttributes naming attributes
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private StringBuffer buildNameFilterString(String aPattern, String aOperator,
+ String[] aObjectClasses, String[] aNamingAttributes,
+ boolean aIsRecursive) throws SPIException {
+ Vector subConditions = new Vector() ;
+ boolean addExclusionFilter =
+ addNameFilters(aObjectClasses, aNamingAttributes,
+ aOperator, aPattern, subConditions) ;
+ StringBuffer retCode = new StringBuffer() ;
+ if (subConditions.size() > 1) {
+ retCode.append("(|") ;
+ int size = subConditions.size();
+ for (int i = 0 ; i < size ; ++ i) {
+ retCode.append(subConditions.get(i)) ;
+ }
+ retCode.append(")") ;
+ } else { retCode.append(subConditions.get(0)) ; }
+ if (addExclusionFilter) {
+ excludeServiceEntriesFromSearchFilter(aIsRecursive, retCode);
+ }
+ return retCode ;
+ }
+
+ /**
+ * Builds an LDAP boolean condition involving the unique
+ * attribute of an item.
+ *
+ * @param aPattern pattern that the attribute must match
+ * @param aOperator LDAP operator to be used for attribute matching
+ * @param aItemMapping item mapping object
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String buildNameFilter(String aPattern, String aOperator,
+ LdapEntityMapping.ItemMapping aItemMapping,
+ boolean aIsRecursive) throws SPIException {
+ Vector subConditions = new Vector() ;
+ addNameFilter(aItemMapping.getObjectClass(), aItemMapping.getUniqueAttribute(),
+ aOperator, aPattern, subConditions) ;
+ StringBuffer retCode = new StringBuffer() ;
+ retCode.append(subConditions.get(0)) ;
+ if (aItemMapping instanceof LdapEntityMapping.UserMapping) {
+ //exclude hosts from search (for Active Directory)
+ retCode.insert(0, "(&(!(" + LdapDataStore.LDAP_OBJCLASS + "="
+ + mEntityMapping.mHostMapping.getObjectClass() +
+ "))");
+ retCode.append(")");
+ }
+ return retCode.toString() ;
+ }
+
+ /**
+ * Adds a series of name filters to vector thereof.
+ *
+ * @param aObjectClasses object classes
+ * @param aNamingAttributes naming attributes
+ * @param aOperator matching operator
+ * @param aPattern matching pattern
+ * @param aFilters vector that will be updated on return
+ * @return <code>true</code> if one of the
+ * objectclasses is organizationalunit
+ */
+ public boolean addNameFilters(String[] aObjectClasses,
+ String[] aNamingAttributes, String aOperator,
+ String aPattern, Vector aFilters) {
+ boolean addExclusionFilter = false;
+ for (int i = 0 ; i < aObjectClasses.length; ++ i) {
+ addNameFilter(aObjectClasses [i], aNamingAttributes [i],
+ aOperator, aPattern, aFilters) ;
+ if (aObjectClasses[i].equalsIgnoreCase(LdapDataStore.ORG_UNIT_OBJCLASS)) {
+ addExclusionFilter = true;
+ }
+ }
+ return addExclusionFilter;
+ }
+
+ /**
+ * Adds an individual name filter to a vector thereof.
+ *
+ * @param aObjectClass object class the entity must have
+ * @param aAttribute attribute to be matched
+ * @param aOperator matching operator
+ * @param aPattern matching pattern
+ * @param aFilters vector that will be updated with
+ * the filter on return
+ */
+ public void addNameFilter(String aObjectClass, String aAttribute,
+ String aOperator, String aPattern,
+ Vector aFilters) {
+ StringBuffer filterBuffer = new StringBuffer("(&(");
+ filterBuffer.append(LdapDataStore.LDAP_OBJCLASS).append("=");
+ filterBuffer.append(aObjectClass).append(")(");
+ filterBuffer.append(aAttribute).append(aOperator);
+ if (aPattern == null) {
+ filterBuffer.append(LdapDataStore.LDAP_WILDCARD);
+ }
+ else {
+ filterBuffer.append(aPattern);
+ }
+ filterBuffer.append("))");
+ aFilters.add(filterBuffer.toString());
+ }
+
+ /**
+ * Returns the mapping of a filter from the SO attributes to
+ * the LDAP attributes.
+ * It is assumed that the type and filter are non-null and valid.
+ *
+ * @param aFilter filter to map
+ * @param aUserMapping user mapping object
+ * @return mapped filter
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public String buildMappedFilter(String aFilter,
+ LdapEntityMapping.UserMapping aUserMapping) throws SPIException {
+ int lastChar = 0;
+ boolean hasExtraParentheses = false;
+ if (aFilter.charAt(0) == '(') {
+ lastChar = 1;
+ hasExtraParentheses = true;
+ }
+ ParsedAttribute attribute = new ParsedAttribute() ;
+ int currentChar = parseNextAttribute(aFilter, lastChar,
+ attribute) ;
+ StringBuffer tmpBuffer = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ Vector subConditions = new Vector();
+ while (currentChar != -1) {
+ tmpBuffer.delete(0, tmpBuffer.length());
+ if (attribute.mAttribute == null ||
+ attribute.mAttribute.length() == 0) {
+ attribute.mAttribute = aUserMapping.getUniqueAttribute();
+ } else {
+ if (attribute.mAttribute == null) {
+ throw new InvalidFilterException(aFilter) ;
+ }
+ }
+ tmpBuffer.append("(").append(attribute.mAttribute).append(
+ attribute.mOperator).append(attribute.mValue).append(")");
+ subConditions.add(tmpBuffer.toString());
+ lastChar = attribute.mLastChar ;
+ currentChar = parseNextAttribute(aFilter, lastChar,
+ attribute) ;
+ }
+ StringBuffer retCode = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ if (subConditions.size() > 1) {
+ retCode.append("(&") ;
+ int size = subConditions.size();
+ for (int i = 0 ; i < size ; ++ i) {
+ retCode.append(subConditions.get(i)) ;
+ }
+ retCode.append(")") ;
+ } else { retCode.append(subConditions.get(0)) ; }
+ return retCode.toString() ;
+ }
+
+ /**
+ * Returns the mapping of a filter from the SO attributes to
+ * the LDAP attributes.
+ * It is assumed that the type and filter are non-null and valid.
+ *
+ * @param aFilter filter to map
+ * @param aHostMapping host mapping object
+ * @return mapped filter
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public String buildMappedFilter(String aFilter,
+ LdapEntityMapping.ItemMapping aHostMapping) throws SPIException {
+ int lastChar = 0;
+ boolean hasExtraParentheses = false;
+ if (aFilter.charAt(0) == '(') {
+ lastChar = 1;
+ hasExtraParentheses = true;
+ }
+ ParsedAttribute attribute = new ParsedAttribute() ;
+ int currentChar = parseNextAttribute(aFilter, lastChar,
+ attribute) ;
+ StringBuffer tmpBuffer = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ Vector subConditions = new Vector();
+ while (currentChar != -1) {
+ tmpBuffer.delete(0, tmpBuffer.length());
+ if (attribute.mAttribute == null ||
+ attribute.mAttribute.length() == 0) {
+ attribute.mAttribute = aHostMapping.getUniqueAttribute();
+ }
+ tmpBuffer.append("(").append(attribute.mAttribute).append(
+ attribute.mOperator).append(attribute.mValue).append(")");
+ subConditions.add(tmpBuffer.toString());
+ lastChar = attribute.mLastChar ;
+ currentChar = parseNextAttribute(aFilter, lastChar,
+ attribute) ;
+ }
+ StringBuffer retCode = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ if (subConditions.size() > 1) {
+ retCode.append("(&") ;
+ int size = subConditions.size();
+ for (int i = 0 ; i < size ; ++ i) {
+ retCode.append(subConditions.get(i)) ;
+ }
+ retCode.append(")") ;
+ } else { retCode.append(subConditions.get(0)) ; }
+ return retCode.toString() ;
+ }
+
+ /**
+ * Maps a filter to use the corresponding LDAP attributes.
+ *
+ * @param aFilter search filter
+ * @param aUserMapping user mapping object
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if the type is invalid.
+ */
+ public String mapFilter(String aFilter,
+ LdapEntityMapping.UserMapping aUserMapping,
+ boolean aIsRecursive) throws SPIException {
+ String classFilter = buildClassFilter(aUserMapping, aIsRecursive) ;
+ if (aFilter == null || aFilter.length() == 0) {
+ return classFilter ;
+ }
+ StringBuffer retCode = new StringBuffer() ;
+ retCode.append("(&").append(classFilter) ;
+ retCode.append(buildMappedFilter(aFilter, aUserMapping));
+ retCode.append(")") ;
+ return retCode.toString() ;
+ }
+
+ /**
+ * Maps a filter to use the corresponding LDAP attributes.
+ *
+ * @param aFilter search filter
+ * @param aHostMapping host mapping object
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return filter string
+ * @throws <code>SPIException</code> if the type is invalid.
+ */
+ public String mapFilter(String aFilter,
+ LdapEntityMapping.ItemMapping aHostMapping,
+ boolean aIsRecursive) throws SPIException {
+ String classFilter = buildClassFilter(aHostMapping, aIsRecursive) ;
+ if (aFilter == null || aFilter.length() == 0) {
+ return classFilter ;
+ }
+ StringBuffer retCode = new StringBuffer() ;
+ retCode.append("(&").append(classFilter) ;
+ retCode.append(buildMappedFilter(aFilter, aHostMapping));
+ retCode.append(")") ;
+ return retCode.toString() ;
+ }
+
+ /**
+ * Adds the role filter to the search filter.
+ *
+ * @param aIsRecursive <code>true</code> if search is
+ * recursive
+ * @param aRetCode the existing search filter
+ */
+ public void addRoleFilterPlus(
+ boolean aIsRecursive, StringBuffer aRetCode) {
+ if (aRetCode == null) { return; }
+ aRetCode.insert(0, "(&");
+ aRetCode.insert(2, LdapRole.ROLE_FILTER_PLUS);
+ aRetCode.append(")");
+ }
+
+ /**
+ * Excludes the service entries from the search filter.
+ *
+ * @param aIsRecursive <code>true</code> if search is
+ * recursive
+ * @param aRetCode the existing search filter
+ */
+ public void excludeServiceEntriesFromSearchFilter(
+ boolean aIsRecursive, StringBuffer aRetCode) {
+ if (aRetCode == null) { return; }
+ StringBuffer filterBuf = new StringBuffer();
+ filterBuf.append("(&");
+ filterBuf.append("(&(!(");
+ filterBuf.append(LdapDataStore.CONFIG_NAMING_ATTR +
+ LdapDataStore.SERVICES);
+ filterBuf.append("))");
+ if (aIsRecursive) {
+ filterBuf.append("(!(");
+ filterBuf.append(LdapDataStore.CONFIG_NAMING_ATTR +
+ LdapDataStore.SERVICE_ORG_CONFIG);
+ filterBuf.append("))");
+ filterBuf.append("(!(");
+ filterBuf.append(LdapDataStore.LDAP_OBJCLASS + "=" +
+ LdapDataStore.SUNSERVICE_COMPONENT_OBJCLASS);
+ filterBuf.append("))");
+ }
+ filterBuf.append(")");
+ aRetCode.insert(0, filterBuf.toString());
+ aRetCode.append(")");
+ }
+
+
+ public static class ParsedAttribute {
+ public String mAttribute ;
+ public String mOperator = "="; //default
+ public String mValue ;
+ public int mLastChar ;
+ }
+
+ private static final String SKIPPABLES = "()|&! \t" ;
+
+ /**
+ * Parses an LDAP filter to the next attribute and fills a
+ * structure with the contents of the attribute condition.
+ *
+ * @param aFilter filter to be parsed
+ * @param aStart starting point of the search
+ * @param aAttribute attribute description filled on return
+ * @return index of the beginning of the expression
+ * @throws SPIException if the format is invalid.
+ */
+ public int parseNextAttribute(String aFilter, int aStart,
+ ParsedAttribute aAttribute) throws SPIException {
+ aAttribute.mAttribute = null;
+ int length = aFilter.length() ;
+ int currentChar = aStart ;
+ // Find the beginning of the attribute if specified
+ while (currentChar < length) {
+ if (SKIPPABLES.indexOf(aFilter.charAt(currentChar)) == -1) {
+ // We found a non-skippable character, may be
+ // the beginning of the attribute.
+ break ;
+ }
+ ++ currentChar ;
+ }
+ if (currentChar >= length) { return -1 ; }
+ // Find the next closing parentheses, if there is one
+ int closing = aFilter.indexOf(")", currentChar);
+ int operation = aFilter.indexOf('=', currentChar) ;
+ if (operation != -1 && (closing == -1 || operation < closing)) {
+ char preOperation = aFilter.charAt(operation - 1) ;
+ if (preOperation == '<' || preOperation == '>' ||
+ preOperation == '~') {
+ aAttribute.mAttribute = aFilter.substring(currentChar,
+ operation - 1) ;
+ aAttribute.mOperator = aFilter.substring(operation - 1,
+ operation + 1) ;
+ } else {
+ if (currentChar < operation) {
+ aAttribute.mAttribute = aFilter.substring(
+ currentChar, operation) ;
+ }
+ aAttribute.mOperator = "=" ;
+ }
+ aAttribute.mLastChar = operation + 1;
+ } else {
+ aAttribute.mLastChar = currentChar;
+ }
+ while (aAttribute.mLastChar < length) {
+ if (aFilter.charAt(aAttribute.mLastChar) == ')' &&
+ aFilter.charAt(aAttribute.mLastChar - 1) != '\\') {
+ break ;
+ }
+ ++ aAttribute.mLastChar ;
+ }
+ if (operation != -1 && (closing == -1 || operation < closing)) {
+ aAttribute.mValue = aFilter.substring(operation + 1,
+ aAttribute.mLastChar) ;
+ } else {
+ aAttribute.mValue = aFilter.substring(currentChar,
+ aAttribute.mLastChar) ;
+ }
+ // Now a bit of normalisation...
+ if (aAttribute.mAttribute != null) {
+ aAttribute.mAttribute = aAttribute.mAttribute.trim().toLowerCase() ;
+ }
+ aAttribute.mValue = aAttribute.mValue.trim() ;
+ return currentChar ;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has roles.
+ *
+ * @return <code>true</code> if there are roles, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasRoles() throws SPIException {
+ return false;
+ }
+
+ /**
+ * Returns the child roles.
+ *
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getRoles () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mRoleMapping, false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.ROLE, mEntityMapping.mRoleMapping.getContainerEntry(),
+ false, returnValue);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the child roles.
+ *
+ * @return array of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getRolesArray () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mRoleMapping, false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.ROLE, mEntityMapping.mRoleMapping.getContainerEntry(),
+ false, returnValue);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns role entities whose attributes match
+ * a given LDAP filter.
+ *
+ * @param aFilter LDAP search filter
+ * @param aRecursive true if recursive search, false otherwise
+ * @return <code>Vector</code/> of <code>Entity</code>s representing
+ * the matching entities
+ * @throws SPIException if error occurs
+ * @throws IllegalReadException if error occurs
+ */
+ public Vector searchForRoles(String aFilter,
+ boolean aRecursive) throws SPIException {
+ StringBuffer baseDnBuf = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ if (mEntityMapping.mRoleMapping.getContainerEntry() != null) {
+ baseDnBuf.append(mEntityMapping.mRoleMapping.getContainerEntry());
+ baseDnBuf.append(LDAP_SEPARATOR);
+ }
+ baseDnBuf.append(mLocation);
+ String []attributes = { LdapDataStore.LDAP_OBJCLASS};
+ Vector results = null;
+ try {
+ results = getDataStore().performSearch(
+ baseDnBuf.toString(),
+ aRecursive, aFilter,
+ attributes, LdapEntity.DN_REQUIRED,
+ LdapEntity.NOT_CHECK_ONLY,
+ null, false, getContext()) ;
+ } catch (IllegalReadException ire) {
+ if (LdapDataStore.getLdapErrorCode(ire)
+ == LDAPException.NO_SUCH_OBJECT) {
+ return new Vector();
+ }
+ throw ire;
+ }
+ // We have to ensure every result is actually mappable
+ // into a proper entity. What can happen is that we get
+ // entries that conform to the filter but that for instance
+ // are not stored under the proper container (role, user or host)
+ // and so must be ignored by us.
+ Vector retCode = new Vector();
+ if (!results.isEmpty()) {
+ int size = results.size();
+ Entity tmpEntity = null;
+ for (int i = 0 ; i < size ; i++) {
+ try {
+ Hashtable attrsValues = (Hashtable)results.get(i);
+ Vector values =
+ (Vector)attrsValues.get(LdapDataStore.DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ tmpEntity = getEntityFromDN((String) values.get(0),
+ LdapEntityType.ROLE, false, attrsValues);
+ }
+ if (tmpEntity != null) {
+ retCode.add(tmpEntity);
+ }
+ } catch (Exception ignore) {
+ /* cannot convert DN to entity, so omit from list */
+ }
+ }
+ }
+ return retCode == null ? new Vector() : retCode;
+ }
+
+ /**
+ * Returns an iterator of profiles
+ * that contribute to this entity's configuration data.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public Iterator getLayeredProfiles()
+ throws SPIException {
+ Iterator parents = getAllParents();
+ return getLayeredProfiles(parents, null);
+ }
+
+
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapOrganization.java b/src/com/sun/apoc/spi/ldap/entities/LdapOrganization.java
new file mode 100644
index 0000000..2f1127c
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapOrganization.java
@@ -0,0 +1,817 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPException;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.InvalidFilterException;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.util.BooleanReturnValue;
+
+/**
+ * Class for an LDAP organization entity.
+ *
+ */
+public class LdapOrganization extends LdapNode implements Organization
+{
+ private LdapOrganization mParent;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId id entry for the user
+ * @param aParentIndex index for parent entity within id
+ * @param aDataStore datastore object
+ * @param aEntityMapping mapping object
+ * @param aContext client context
+ */
+ public LdapOrganization (String aId, int aParentIndex, LdapDataStore aDataStore,
+ LdapEntityMapping aEntityMapping, LdapClientContext aContext) {
+ super(aId, aParentIndex, aDataStore, aEntityMapping, aContext);
+ }
+
+ /**
+ * Tests for equality with another Entity.
+ *
+ * @param aEntity other entity
+ * @return <code>true</code> if both entities are
+ * equal, otherwise <code>false</code>
+ */
+ public boolean equals (Object aEntity) {
+ if (aEntity instanceof LdapOrganization) {
+ return LDAPDN.equals(mLocation.toLowerCase(),
+ ((LdapOrganization) aEntity).mLocation.toLowerCase()) ;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the child organizations, roles and users.
+ *
+ * @return <code>Iterator</code> of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getChildren() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ return getChildren(LdapEntity.NOT_CHECK_ONLY, returnValue);
+ }
+
+ /**
+ * Returns the child organizations, roles and users.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are children, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return <code>Iterator</code> of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getChildren(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector allChildren = getAllChildrenList(aCheckOnly, aReturnValue);
+ return allChildren.iterator();
+ }
+
+ /**
+ * Returns the child organizations, roles and users.
+ *
+ * @return array of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getChildrenArray() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ return getChildrenArray(LdapEntity.NOT_CHECK_ONLY, returnValue);
+ }
+
+ /**
+ * Returns the child organizations, roles and users.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are children, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return array of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getChildrenArray(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector allChildren = getAllChildrenList(aCheckOnly, aReturnValue);
+ Entity[] entities = new Entity[allChildren.size()];
+ for (int i = 0; i < allChildren.size(); ++i) {
+ Object tester = allChildren.get(i);
+ entities[i] = (Entity)allChildren.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this entity
+ * has children.
+ *
+ * @return <code>true</code> if there are children, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasChildren() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ getChildren(LdapEntity.CHECK_ONLY, returnValue);
+ return returnValue.getReturnValue();
+ }
+
+
+ /**
+ * Returns the list child organizations, roles and users.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are children, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return <code>Vector</code> of children
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector getAllChildrenList(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector allChildren = new Vector();
+ String container = null;
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mOrganizationMapping,
+ false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.ORG, container, aCheckOnly, aReturnValue);
+ if (aCheckOnly && aReturnValue.getReturnValue()) { return allChildren; }
+ allChildren.addAll(childrenList);
+ searchFilter = buildClassFilter(
+ mEntityMapping.mRoleMapping,
+ false);
+ childrenList = getChildrenList (searchFilter,
+ LdapEntityType.ROLE, container, aCheckOnly, aReturnValue);
+ if (aCheckOnly && aReturnValue.getReturnValue()) { return allChildren; }
+ allChildren.addAll(childrenList);
+ searchFilter = buildClassFilter(
+ mEntityMapping.mUserMapping,
+ false);
+ container =
+ mEntityMapping.mUserMapping.getContainerEntry();
+ childrenList = getChildrenList (searchFilter,
+ LdapEntityType.USERID, container, aCheckOnly, aReturnValue);
+ if (aCheckOnly && aReturnValue.getReturnValue()) { return allChildren; }
+ if (childrenList!=null) {
+ allChildren.addAll(childrenList);
+ }
+ return allChildren;
+ }
+
+
+ /**
+ * Returns the suborganizations.
+ *
+ * @return <code>Iterator</code> of child organizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getSubOrganizations () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mOrganizationMapping,
+ false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.ORG, null, false, returnValue);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the suborganizations.
+ *
+ * @return array of suborganizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getSubOrganizationsArray () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mOrganizationMapping,
+ false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.ORG, null, false, returnValue);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns the users.
+ *
+ * @return <code>Iterator</code> of child users
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getUsers () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mUserMapping, false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.USERID,
+ mEntityMapping.mUserMapping.getContainerEntry(),
+ false, returnValue);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the users.
+ *
+ * @return array of child users
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getUsersArray () throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ String searchFilter = buildClassFilter(
+ mEntityMapping.mUserMapping, false);
+ Vector childrenList = getChildrenList (searchFilter,
+ LdapEntityType.USERID,
+ mEntityMapping.mUserMapping.getContainerEntry(),
+ false, returnValue);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Finds the suborganizations that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child organizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findSubOrganizationsByName (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubOrganizationsByNameList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the suborganizations that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of suborganizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findSubOrganizationsByNameArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubOrganizationsByNameList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+ /**
+ * Finds the suborganizations that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child organizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findSubOrganizationsByFilter (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubOrganizationsByFilterList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the suborganizations that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of suborganizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findSubOrganizationsByFilterArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findSubOrganizationsByFilterList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Finds the users that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child users
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findUsersByName (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findUsersByNameList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the users that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of users
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findUsersByNameArray (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findUsersByNameList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+ /**
+ * Finds the users that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child users
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator findUsersByFilter (String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ Vector childrenList =
+ findUsersByFilterList(aFilter, aIsRecursive);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the users that match the filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of users
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] findUsersByFilterArray (String aFilter,
+ boolean aIsRecursive)
+ throws SPIException {
+ Vector childrenList =
+ findUsersByFilterList (aFilter, aIsRecursive);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns the parent organization.
+ *
+ * @return parent organization
+ */
+ public Entity getParent() {
+ if (mParent == null && mParentIndex != -1) {
+ String [] elements = LDAPDN.explodeDN(mLocation, false) ;
+ if (elements == null ||
+ mParentIndex >= elements.length) {
+ return null;
+ }
+ StringBuffer dn = new StringBuffer(elements [mParentIndex]) ;
+ for (int i = mParentIndex + 1 ; i < elements.length ; ++ i) {
+ dn.append(LDAP_SEPARATOR).append(elements [i]) ;
+ }
+ mParent = (LdapOrganization) getEntityFromDN(dn.toString(), LdapEntityType.ORG, false,
+ null);
+ }
+ return mParent;
+ }
+
+ /**
+ * Finds the entities within this organization that match the
+ * specified filter. The entities can be organizations, roles, or
+ * users.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findEntitiesByNameList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector allEntities = findUsersByNameList(aFilter, aIsRecursive);
+ Vector orgEntities = findSubOrganizationsByNameList(aFilter,
+ aIsRecursive);
+ for (int i = 0; i < orgEntities.size(); ++i) {
+ allEntities.add(orgEntities.get(i));
+ }
+ Vector roleEntities = findRolesByNameList(aFilter, aIsRecursive);
+ for (int i = 0; i < roleEntities.size(); ++i) {
+ allEntities.add(roleEntities.get(i));
+ }
+ return allEntities;
+ }
+
+ /**
+ * Finds the organizations within this organization that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findSubOrganizationsByNameList(String aFilter,
+ boolean aIsRecursive) throws SPIException {
+ String nameFilter = buildNameFilter(aFilter, "=",
+ mEntityMapping.mOrganizationMapping, aIsRecursive);
+ Vector subEntities = searchForOrganizations(nameFilter,
+ aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Finds the users within this organization that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findUsersByNameList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ String nameFilter = buildNameFilter(aFilter, "=",
+ mEntityMapping.mUserMapping, aIsRecursive);
+ Vector subEntities = searchForUsers(nameFilter, aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Finds the entities within this organization that match the
+ * specified filter. The entities can be organizations, roles, or
+ * users.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findEntitiesByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector allEntities = findUsersByFilterList(aFilter, aIsRecursive);
+ Vector orgEntities =
+ findSubOrganizationsByFilterList(aFilter, aIsRecursive);
+ for (int i = 0; i < orgEntities.size(); ++i) {
+ allEntities.add(orgEntities.get(i));
+ }
+ Vector roleEntities = findRolesByFilterList(aFilter, aIsRecursive);
+ for (int i = 0; i < roleEntities.size(); ++i) {
+ allEntities.add(roleEntities.get(i));
+ }
+ return allEntities;
+ }
+
+ /**
+ * Finds the suborganizations within this organization that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child organizations
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findSubOrganizationsByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ String mapFilter = mapFilter(aFilter,
+ mEntityMapping.mOrganizationMapping, aIsRecursive);
+ Vector subEntities = searchForOrganizations(mapFilter,
+ aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Finds the users within this organization that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child users
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findUsersByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ String mapFilter = mapFilter(aFilter,
+ mEntityMapping.mUserMapping, aIsRecursive);
+ Vector subEntities = searchForUsers(mapFilter, aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Returns organization entities whose attributes match
+ * a given LDAP filter.
+ *
+ * @param aFilter LDAP search filter
+ * @param aRecursive true if recursive search, false otherwise
+ * @return <code>Vector</code> of <code>EntityId</code>s representing
+ * the matching entities
+ * @throws SPIException if error occurs
+ * @throws IllegalReadException if error occurs
+ */
+ private Vector searchForOrganizations(String aFilter,
+ boolean aRecursive) throws SPIException {
+ StringBuffer baseDnBuf = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ String []attributes = { LdapDataStore.LDAP_OBJCLASS};
+ Vector results =null;
+ try {
+ results = getDataStore().performSearch(mLocation,
+ aRecursive, aFilter,
+ attributes, LdapEntity.DN_REQUIRED,
+ LdapEntity.NOT_CHECK_ONLY,
+ null, false, getContext()) ;
+ } catch (IllegalReadException ire) {
+ if (LdapDataStore.getLdapErrorCode(ire)
+ == LDAPException.NO_SUCH_OBJECT) {
+ return new Vector();
+ }
+ throw ire;
+ }
+ // We have to ensure every result is actually mappable
+ // into a proper entity. What can happen is that we get
+ // entries that conform to the filter but that for instance
+ // are not stored under the proper container (role, user or host)
+ // and so must be ignored by us.
+ Vector retCode = new Vector();
+ if (!results.isEmpty()) {
+ int size = results.size();
+ Entity tmpEntity = null;
+ for (int i = 0 ; i < size ; i++) {
+ try {
+ Hashtable attrsValues = (Hashtable)results.get(i);
+ Vector values =
+ (Vector)attrsValues.get(LdapDataStore.DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ tmpEntity = getEntityFromDN((String) values.get(0),
+ LdapEntityType.ORG, false, attrsValues);
+ }
+ if (tmpEntity != null) {
+ /* if it is a recursive search then need
+ to exclude the start organization from
+ the results */
+ boolean excludeThisEntity = aRecursive;
+ if (excludeThisEntity) {
+ if (!this.equals(tmpEntity)) {
+ retCode.add(tmpEntity) ;
+ } else {
+ // have excluded the start entity
+ excludeThisEntity = false;
+ }
+ } else {
+ retCode.add(tmpEntity) ;
+ }
+ }
+ } catch (Exception ignore) {
+ /* cannot convert DN to entity, so omit from list */
+ }
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns user entities whose attributes match
+ * a given LDAP filter.
+ *
+ * @param aFilter LDAP search filter
+ * @param aRecursive true if recursive search, false otherwise
+ * @return <code>Vector</code/> of <code>Entity</code>s representing
+ * the matching entities
+ * @throws SPIException if error occurs
+ * @throws IllegalReadException if error occurs
+ */
+ private Vector searchForUsers(String aFilter,
+ boolean aRecursive) throws SPIException {
+ StringBuffer baseDnBuf = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ String [] attributes =
+ new String[2 + mEntityMapping.mUserMapping.getDisplayAttributes().length];
+ attributes[0] = LdapDataStore.LDAP_OBJCLASS;
+ attributes[1] =
+ mEntityMapping.mUserMapping.getUniqueAttribute();
+ int index = 2;
+ for (int i = 0; i <
+ mEntityMapping.mUserMapping.getDisplayAttributes().length; ++i) {
+ attributes[index++] =
+ mEntityMapping.mUserMapping.getDisplayAttributes()[i];
+ }
+ if (!aRecursive) {
+ String container = mEntityMapping.mUserMapping.getContainerEntry();
+ if (container != null && container != "") {
+ baseDnBuf.append(container).append(LdapEntity.LDAP_SEPARATOR);
+ }
+ }
+ baseDnBuf.append(mLocation);
+ Vector results = null;
+ try {
+ results = getDataStore().performSearch(
+ baseDnBuf.toString(),
+ aRecursive, aFilter,
+ attributes, LdapEntity.DN_REQUIRED,
+ LdapEntity.NOT_CHECK_ONLY,
+ null, false, getContext()) ;
+ } catch (IllegalReadException ire) {
+ if (LdapDataStore.getLdapErrorCode(ire)
+ == LDAPException.NO_SUCH_OBJECT) {
+ return new Vector();
+ }
+ throw ire;
+ }
+ // We have to ensure every result is actually mappable
+ // into a proper entity. What can happen is that we get
+ // entries that conform to the filter but that for instance
+ // are not stored under the proper container (role, user or host)
+ // and so must be ignored by us.
+ Vector retCode = new Vector();
+ if (!results.isEmpty()) {
+ int size = results.size();
+ Entity tmpEntity = null;
+ for (int i = 0 ; i < size ; i++) {
+ try {
+ Hashtable attrsValues = (Hashtable)results.get(i);
+ Vector values =
+ (Vector)attrsValues.get(LdapDataStore.DN_KEY);
+ if (values != null && !values.isEmpty()) {
+ tmpEntity = getEntityFromDN((String) values.get(0),
+ LdapEntityType.USERID, false, attrsValues);
+ }
+ if (tmpEntity != null) {
+ retCode.add(tmpEntity);
+ }
+ } catch (Exception ignore) {
+ /* cannot convert DN to entity, so omit from list */
+ }
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns organizations that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for organizations
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of organization objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Iterator findSubOrganizations(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findSubOrganizationsByFilter(aFilter, aIsRecursive);
+ } else {
+ return findSubOrganizationsByName(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Returns organizations that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for organizations
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of organizations objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Entity[] findSubOrganizationsArray(String aFilter, boolean aIsRecursive)
+ throws SPIException{
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findSubOrganizationsByFilterArray(aFilter, aIsRecursive);
+ } else {
+ return findSubOrganizationsByNameArray(aFilter, aIsRecursive);
+ }
+ }
+
+
+ /**
+ * Returns users that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for users
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of user objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Iterator findUsers(String aFilter, boolean aIsRecursive) throws SPIException{
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findUsersByFilter(aFilter, aIsRecursive);
+ } else {
+ return findUsersByName(aFilter, aIsRecursive);
+ }
+ }
+
+ /**
+ * Returns users that match the specified filter.
+ *
+ * @param aFilter the filter to use in searching for users
+ * @param aIsRecursive <code>true</code> if recursive search required,
+ * otherwise <code>false</code>
+ * @return array of user objects
+ * @throws SPIException if error occurs
+ * @throws InvalidFilterException if aFilter is null
+ */
+ public Entity[] findUsersArray(String aFilter, boolean aIsRecursive) throws SPIException{
+ if (aFilter == null) {
+ throw new InvalidFilterException();
+ }
+ if (aFilter.startsWith(LdapNode.SEARCH_FILTER_DELIMITER)) {
+ return findUsersByFilterArray(aFilter, aIsRecursive);
+ } else {
+ return findUsersByNameArray(aFilter, aIsRecursive);
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapOrganizationProvider.java b/src/com/sun/apoc/spi/ldap/entities/LdapOrganizationProvider.java
new file mode 100644
index 0000000..92ef6e0
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapOrganizationProvider.java
@@ -0,0 +1,99 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.entities;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.AbstractEntity;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.entities.OrganizationTreeProvider;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.ldap.LdapConnectionHandler;
+/**
+ * Provides access to a organization tree stored in a LDAP backend
+ *
+ */
+public class LdapOrganizationProvider
+ extends LdapEntityProvider implements OrganizationTreeProvider {
+
+ public LdapOrganizationProvider(PolicySource aPolicySource, String url)
+ throws SPIException {
+ super(aPolicySource, url);
+ }
+
+ /**
+ * Opens the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws OpenConnectionException if connection error occurs
+ * @throws CloseConnectionException if connection error occurs
+ * @throws AuthenticateException if connection error occurs
+ */
+ public void open() throws SPIException {
+ if ((mConnection == null) && (mEnvironmentMgr != null)) {
+ mConnection = new LdapConnectionHandler();
+ mConnection.connect(mURL,
+ mEnvironmentMgr.getOrganizationTimeout(),
+ mEnvironmentMgr.getOrganizationAuthUser(),
+ mEnvironmentMgr.getOrganizationAuthPassword(),
+ mEnvironmentMgr);
+ if (isGSSAPIAuthentication()){
+ Object callbackHandler =
+ mEnvironmentMgr.getOrganizationCallbackHandler();
+ mConnection.authenticate(callbackHandler);
+ }
+ else {
+ mConnection.authenticate(mEnvironmentMgr.getOrganizationUser(mURL),
+ mEnvironmentMgr.getOrganizationCredentials());
+ }
+ mConnection.closeAuthorizedContext();
+
+ // store the new LdapConnectionHandler in the PolicyManager
+ mPolicySource.setConnectionHandler(mURL, mConnection);
+ }
+ mDataStore = mConnection.getDataStore();
+ mRootNode = mDataStore.getRootOrganization();
+ ((AbstractEntity)mRootNode).setPolicySource(mPolicySource);
+ }
+
+ protected boolean isGSSAPIAuthentication() {
+ return mEnvironmentMgr.getOrganizationAuthType()
+ .equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI);
+ }
+
+ public Organization getRootOrganization() throws SPIException
+ {
+ return (Organization)super.getRootEntity();
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapRole.java b/src/com/sun/apoc/spi/ldap/entities/LdapRole.java
new file mode 100644
index 0000000..aaab228
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapRole.java
@@ -0,0 +1,500 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPException;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Role;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.util.BooleanReturnValue;
+
+/**
+ * Class for an LDAP role entity.
+ *
+ */
+public class LdapRole extends LdapNode implements Role
+{
+ private Entity mParent;
+ private Entity mParentOrgOrDomain;
+
+ public static final String ROLE_FILTER_PLUS =
+ "(" + LdapDataStore.LDAP_OBJCLASS + "=ldapsubentry)";
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId id entry for the user
+ * @param aParentIndex index for parent entity within id
+ * @param aDataStore datastore object
+ * @param aEntityMapping mapping object
+ * @param aContext client context
+ */
+ public LdapRole (String aId, int aParentIndex, LdapDataStore aDataStore,
+ LdapEntityMapping aEntityMapping, LdapClientContext aContext) {
+ super(aId, aParentIndex, aDataStore, aEntityMapping, aContext);
+ }
+
+ /**
+ * Tests for equality with another Entity.
+ *
+ * @param aEntity other entity
+ * @return <code>true</code> if both entities are
+ * equal, otherwise <code>false</code>
+ */
+ public boolean equals (Object aEntity) {
+ if (aEntity instanceof LdapRole) {
+ return LDAPDN.equals(mLocation.toLowerCase(),
+ ((LdapRole) aEntity).mLocation.toLowerCase()) ;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this role
+ * has members.
+ *
+ * @return <code>true</code> if there are members, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasMembers() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ getMembers(LdapEntity.CHECK_ONLY, returnValue);
+ return returnValue.getReturnValue();
+ }
+
+ /**
+ * Returns the members for this role.
+ *
+ * @return <code>Iterator</code> of member entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getMembers() throws SPIException{
+ return getMembers(LdapEntity.NOT_CHECK_ONLY, null);
+ }
+
+ /**
+ * Returns the members for this role.
+ *
+ * @return array of member entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getMembersArray() throws SPIException{
+ return getMembersArray(LdapEntity.NOT_CHECK_ONLY, null);
+ }
+
+ /**
+ * Returns the members for this role.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are members, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return <code>Iterator</code> of member entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Iterator getMembers(boolean aCheckOnly, BooleanReturnValue aReturnValue)
+ throws SPIException{
+ Vector entityList = null;
+ entityList = searchForMembers(aCheckOnly, aReturnValue);
+ return entityList.iterator();
+ }
+
+ /**
+ * Returns the members for this role.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are members, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return array of member entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Entity[] getMembersArray(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue)
+ throws SPIException{
+ Vector entityList = null;
+ Entity[] entities = null;
+ entityList = searchForMembers(aCheckOnly, aReturnValue);
+ if (!aCheckOnly && entityList != null) {
+ int numOfMembers = entityList.size();
+ entities = new Entity[numOfMembers];
+ for (int i = 0; i < numOfMembers; ++i) {
+ entities[i] = (Entity)entityList.get(i);
+ }
+ }
+ return (entities == null) ? new Entity[0] : entities;
+ }
+
+ /**
+ * Returns the child roles.
+ *
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getChildren() throws SPIException {
+ return getChildren(LdapEntity.NOT_CHECK_ONLY, null);
+ }
+
+ /**
+ * Returns the child roles.
+ *
+ * @return array of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getChildrenArray() throws SPIException {
+ return getChildrenArray(LdapEntity.NOT_CHECK_ONLY, null);
+ }
+
+ /**
+ * Returns the child roles.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are members, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return <code>Iterator</code> of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Iterator getChildren (boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector childrenList = getChildrenList(
+ buildClassFilter(mEntityMapping.mRoleMapping, false),
+ LdapEntityType.ROLE, mEntityMapping.mRoleMapping.getContainerEntry(),
+ aCheckOnly, aReturnValue);
+ return childrenList.iterator();
+ }
+
+ /**
+ * Returns the child roles.
+ *
+ * @param aCheckOnly <code>true</code> if just checking
+ * there are members, otherwise <code>false</code>
+ * @param aReturnValue used if just checking if there are children to
+ * return a value of <code>true</code> or
+ * <code>false</code>
+ * @return array of child roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Entity[] getChildrenArray (boolean aCheckOnly,
+ BooleanReturnValue aReturnValue) throws SPIException {
+ Vector childrenList = getChildrenList(
+ buildClassFilter(mEntityMapping.mRoleMapping, false),
+ LdapEntityType.ROLE, mEntityMapping.mRoleMapping.getContainerEntry(),
+ aCheckOnly, aReturnValue);
+ Entity[] entities = new Entity[childrenList.size()];
+ for (int i = 0; i < childrenList.size(); ++i) {
+ entities[i] = (Entity)childrenList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this role
+ * has children.
+ *
+ * @return <code>true</code> if there are children, otherwise
+ * <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasChildren() throws SPIException {
+ BooleanReturnValue returnValue =
+ new BooleanReturnValue(false);
+ getChildren(LdapEntity.CHECK_ONLY, returnValue);
+ return returnValue.getReturnValue();
+ }
+
+
+ /**
+ * Returns the parent entity. The parent could be a role, an
+ * organization or a domain entity.
+ *
+ * @return parent entity
+ */
+ public Entity getParent() {
+ if (mParent == null) {
+ mParent = getParentRole();
+ if (mParent == null) {
+ String [] elements = LDAPDN.explodeDN(mLocation, false) ;
+ if (elements == null || mParentIndex >= elements.length) {
+ return null;
+ }
+ StringBuffer dn = new StringBuffer(elements [mParentIndex]) ;
+ for (int i = mParentIndex + 1 ; i < elements.length ; ++ i) {
+ dn.append(LDAP_SEPARATOR).append(elements [i]) ;
+ }
+ mParent = getEntityFromDN(dn.toString(), LdapEntityType.UNKNOWN, false,
+ null);
+ }
+ }
+ return mParent;
+ }
+
+ /**
+ * Returns the parent organization or domain entity.
+ *
+ * @return parent organization or domain entity
+ */
+ public Entity getParentOrgOrDomain() {
+ if (mParentOrgOrDomain == null) {
+ mParentOrgOrDomain = getParent();
+ while (mParentOrgOrDomain instanceof LdapRole) {
+ mParentOrgOrDomain = mParentOrgOrDomain.getParent();
+ }
+ }
+ return mParentOrgOrDomain;
+ }
+
+ /**
+ * Returns the entity parent located between this entity and its
+ * container entry (either dedicated one or marked by the parent
+ * index). It will be by definition of the same type as this
+ * entity.
+ *
+ * @return entity id representing the sub-container parent or null
+ */
+ private LdapRole getParentRole() {
+ if (mParentIndex == -1) { return null ; }
+ // The parent has to be located below the parent index.
+ int potential = mParentIndex - 1 ;
+ // And below the container if it exists.
+ if (mEntityMapping.mRoleMapping.getContainerEntry() != null) {
+ -- potential ;
+ }
+ // If we're back to the entry itself we lose.
+ if (potential < 1) { return null ; }
+ String [] elements = LDAPDN.explodeDN(mLocation, false) ;
+ if (elements == null || elements.length == 0) { return null; }
+ StringBuffer dn = new StringBuffer(elements [1]) ;
+ for (int i = 2 ; i < elements.length ; ++ i) {
+ dn.append(LDAP_SEPARATOR).append(elements [i]) ;
+ }
+ LdapRole retCode = new LdapRole(dn.toString(), mParentIndex - 1,
+ getDataStore(), mEntityMapping, getContext());
+ return retCode;
+ }
+
+ /**
+ * Searches for members of the role. Depending on the type
+ * on the type of search specified by the parameter aCheckOnly,
+ * the method will either just ascertain if the role has members,
+ * or else return a list of <code>Entity</code>s for these children.
+ *
+ * @param aCheckOnly if <code>true</code> then just checks if
+ * there are members, otherwise returns the members
+ * @param aReturnValue if just checking if there are members then
+ * this will indicate if there are members,
+ * <code>true</code>, or if there are none,
+ * <code>false</code>
+ * @return list of member <code>Entity</code>s
+ * @throws <code>SPIException</code> if
+ * error occurs
+ */
+ private Vector searchForMembers(boolean aCheckOnly,
+ BooleanReturnValue aReturnValue)
+ throws SPIException {
+ Entity startEntity = getParentOrgOrDomain();
+ Vector returnList = null;
+ try {
+ returnList = (getDataStore()).getRoleMembers(this,
+ mEntityMapping.mUserMapping.getObjectClass(),
+ mEntityMapping.mRoleMapping.getMemberAttribute(),
+ mEntityMapping.mUserMapping.getDisplayAttributes(),
+ aCheckOnly, aReturnValue);
+ /* if just checking if role has members, and it does, then
+ can return here */
+ if (aCheckOnly == LdapEntity.CHECK_ONLY) {
+ return new Vector();
+ }
+ } catch (SPIException spie) {
+ int error = LdapDataStore.getLdapErrorCode(spie);
+ if ( (error != LDAPException.NO_RESULTS_RETURNED)
+ && (error != LDAPException.NO_SUCH_ATTRIBUTE)
+ && (error != LDAPException.NO_SUCH_OBJECT) ) {
+ throw spie;
+ }
+ }
+ Vector retCode = new Vector();
+ if (returnList != null && !returnList.isEmpty()) {
+ int size = returnList.size();
+ Hashtable nameValues = null;
+ Entity tmpEntity = null;
+ for (int i = 0; i < size; i++) {
+ Hashtable attrsValues = (Hashtable)returnList.get(i);
+ try {
+ Vector values =
+ (Vector)attrsValues.get(LdapDataStore.DN_KEY);
+ String dN = (String)values.get(0);
+ tmpEntity = getEntityFromDN(dN,
+ LdapEntityType.USERID, false,
+ attrsValues);
+ if (tmpEntity != null) {
+ retCode.add(tmpEntity);
+ }
+ tmpEntity = null;
+ } catch (Exception ignore) {
+ /* problem with id, so ignore */
+ }
+ }
+ }
+ return retCode == null ? new Vector() : retCode;
+ }
+
+ /**
+ * Finds the roles within this role that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findEntitiesByNameList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector subEntities;
+ subEntities = searchForRoles(
+ buildNameFilter(aFilter,
+ "=", mEntityMapping.mRoleMapping,
+ aIsRecursive),
+ aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Finds the roles within this role that match the
+ * specified filter.
+ *
+ * @param aFilter the search filter
+ * @param aIsRecursive <code>true</code> if recursive search,
+ * otherwise <code>false</code>
+ * @return <code>Iterator</code> of child entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Vector findEntitiesByFilterList(String aFilter, boolean aIsRecursive)
+ throws SPIException {
+ Vector subEntities;
+ subEntities= searchForRoles(
+ mapFilter(aFilter, mEntityMapping.mRoleMapping,
+ aIsRecursive), aIsRecursive);
+ return subEntities;
+ }
+
+ /**
+ * Returns the entity for this id. Entity can only be a role.
+ *
+ * @param aId id string
+ * @return entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity(String aId) throws SPIException {
+ return getEntityFromDN(aId, LdapEntityType.UNKNOWN, false, null);
+ }
+
+ /**
+ * Returns the child role for this id.
+ *
+ * @param aId id string
+ * @return child <code>Role</code> with this id
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Role getRole(String aId) throws SPIException {
+ return null;
+ }
+
+ /**
+ * Returns an iterator over all the role parents for this role.
+ *
+ * @return iterator over all the role parents for this role.
+ */
+ public Iterator getAllParentRoles() {
+ ArrayList parents = new ArrayList();
+ LdapRole parent = getParentRole();
+ while (parent != null) {
+ parents.add(parent);
+ parent = parent.getParentRole();
+ }
+ return parents.iterator();
+ }
+
+ /**
+ * Returns an iterator over all the organization or
+ * domain parents for this role.
+ *
+ * @return iterator over all the non-role parents for this role.
+ */
+ public Iterator getAllOrgOrDomainParents() {
+ ArrayList parents = new ArrayList();
+ Entity parent = getParentOrgOrDomain();
+ while (parent != null) {
+ parents.add(parent);
+ parent = parent.getParent();
+ }
+ return parents.iterator();
+ }
+
+ /**
+ * Returns an iterator of profiles
+ * that contribute to this entity's configuration data.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public Iterator getLayeredProfiles()
+ throws SPIException {
+ Iterator parents = getAllOrgOrDomainParents();
+ Iterator roles = getAllParentRoles();
+ return getLayeredProfiles(parents, roles);
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/LdapUser.java b/src/com/sun/apoc/spi/ldap/entities/LdapUser.java
new file mode 100644
index 0000000..848304b
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/LdapUser.java
@@ -0,0 +1,268 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPException;
+
+import com.sun.apoc.spi.IllegalReadException;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.User;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.ldap.profiles.LdapUserProfile;
+import com.sun.apoc.spi.profiles.Profile;
+
+/**
+ * Interface for an entity.
+ *
+ */
+public class LdapUser extends LdapEntity implements User
+{
+ private static final String USER_ID_KEY = "uid";
+ private static final String KEY_VALUE_SEPARATOR = "=";
+ private LdapOrganization mParent;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId id entry for the user
+ * @param aParentIndex index for parent entity within id
+ * @param aDataStore datastore object
+ * @param aEntityMapping mapping object
+ * @param aContext client context
+ */
+ public LdapUser (String aId, int aParentIndex, LdapDataStore aDataStore,
+ LdapEntityMapping aEntityMapping, LdapClientContext aContext) {
+ super(aId, aParentIndex, aDataStore, aEntityMapping, aContext);
+ }
+
+ /**
+ * Returns the userid for this user.
+ *
+ * @return the userid
+ */
+ public String getUserId() {
+ String uniqueIdKey = mEntityMapping.mUserMapping.getUniqueAttribute();
+ if ((uniqueIdKey == null) || (uniqueIdKey.equals(""))) {
+ uniqueIdKey = USER_ID_KEY;
+ }
+ uniqueIdKey += KEY_VALUE_SEPARATOR;
+ String uid = new String("");
+ String [] elements = LDAPDN.explodeDN(mLocation, true);
+ if ((elements != null) && (elements.length > 0)) {
+ uid = LDAPDN.unEscapeRDN(elements[0]) ;
+ }
+ return uid;
+ }
+
+ /**
+ * Tests for equality with another Entity.
+ *
+ * @param aEntity other entity
+ * @return <code>true</code> if both entities are
+ * equal, otherwise <code>false</code>
+ */
+ public boolean equals (Object aEntity) {
+ if (aEntity instanceof LdapUser) {
+ return LDAPDN.equals(mLocation.toLowerCase(),
+ ((LdapUser) aEntity).mLocation.toLowerCase()) ;
+ }
+ return false;
+ }
+
+ /**
+ * Computes and sets the display name from a list of attributes and
+ * their values.
+ *
+ * @param aValues attribute to value hashtable
+ * @param aAttributes attributes to look for
+ * @param aFormat display format to use
+ */
+ public void setDisplayName(Hashtable aValues, String [] aAttributes,
+ String aFormat) {
+ if (aValues == null || aAttributes == null || aFormat == null) {
+ return ;
+ }
+ StringBuffer displayName = new StringBuffer() ;
+ boolean appended = false;
+ for (int i = 0 ; i < aAttributes.length ; ++ i) {
+ Vector values = (Vector)aValues.get(aAttributes[i]);
+ String value = null;
+ if (values != null && ! values.isEmpty()) {
+ value = (String) values.get(0) ;
+ }
+ if (value != null) {
+ if (appended) { displayName.append(", ") ; }
+ displayName.append(value) ;
+ appended = true;
+ }
+ }
+ if (displayName.length() > 0) {
+ mDisplayName = displayName.toString() ;
+ }
+ }
+
+ /**
+ * Returns the parent organization entity.
+ *
+ * @return parent organization entity
+ */
+ public Entity getParent() {
+ if (mParent == null) {
+ String [] elements = LDAPDN.explodeDN(mLocation, false) ;
+ if (elements == null || mParentIndex >= elements.length) {
+ return null;
+ }
+ StringBuffer dn = new StringBuffer(elements [mParentIndex]) ;
+ for (int i = mParentIndex + 1 ; i < elements.length ; ++ i) {
+ dn.append(LDAP_SEPARATOR).append(elements [i]) ;
+ }
+ mParent = (LdapOrganization) getEntityFromDN(dn.toString(),
+ LdapEntityType.ORG,
+ false, null) ;
+
+ }
+ return mParent;
+ }
+
+ /**
+ * Return list of roles of which this user is a member.
+ *
+ * @return <code>Iterator</code> listing roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getMemberships() throws SPIException {
+ return getListOfRoles().iterator();
+ }
+
+ /**
+ * Return list of roles of which this user is a member.
+ *
+ * @return array listing roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity[] getMembershipsArray() throws SPIException {
+ Vector roleList = getListOfRoles();
+ Entity[] entities = new Entity[roleList.size()];
+ for (int i = 0; i < entities.length; ++i) {
+ entities[i] = (Entity)roleList.get(i);
+ }
+ return entities;
+ }
+
+ /**
+ * Returns the roles of which this user is a member. Roles
+ * are found by reading the computed user attribute
+ *
+ * @return <code>Vector</code> of roles
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private Vector getListOfRoles() throws SPIException {
+ Vector roleList = getDataStore().getListedRolesForEntity(
+ this, mEntityMapping.mRoleMapping.getListingAttribute(),
+ getContext());
+ Vector retCode = new Vector();
+ if (!roleList.isEmpty()) {
+ int size = roleList.size();
+ Entity tmpEntity = null;
+ for (int i = 0; i < size; i++) {
+ try {
+ /* read the entry for this role in order
+ to obtain corret display name for Entity */
+ String dn = getDataStore().readEntryDN(
+ (String)roleList.get(i), getContext());
+ tmpEntity = getEntityFromDN((String)roleList.get(i),
+ LdapEntityType.ROLE, false, null);
+ if (tmpEntity != null) {
+ retCode.add(tmpEntity);
+ }
+ } catch (SPIException ignore) {
+ /* problem converting this DN, so omit it */
+ }
+ }
+ }
+ return retCode;
+ }
+
+ /**
+ * Returns an iterator of profiles
+ * that contribute to this entity's configuration data.
+ * The first element of the iterator has the lowest priority,
+ * the last element has the highest priority.
+ *
+ * @return iterator of hierarchical profiles
+ * @throws <code>SPIException</code> if error
+ * occurs
+ */
+ public Iterator getLayeredProfiles()
+ throws SPIException {
+ Iterator parents = getAllParents();
+ Iterator roles = getMemberships();
+ return getLayeredProfiles(parents, roles);
+ }
+
+ /**
+ * Returns the virtual user profile for this user
+ * containing the values of the user's ldap attributes
+ *
+ * @return the user profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getUserProfile() throws SPIException {
+ LdapUserProfile userProfile = null;
+ Hashtable ldapAttributeTable = null;
+ try {
+ ldapAttributeTable =
+ getDataStore().readAllAttributes(mLocation, getContext());
+ } catch (LDAPException ldape) {
+ throw new IllegalReadException(
+ IllegalReadException.LDAP_READ_KEY, ldape);
+ }
+
+ if (ldapAttributeTable != null) {
+ userProfile = new LdapUserProfile(this, ldapAttributeTable);
+ }
+ return userProfile;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/entities/mapping/LdapEntityMapping.java b/src/com/sun/apoc/spi/ldap/entities/mapping/LdapEntityMapping.java
new file mode 100644
index 0000000..5647036
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/entities/mapping/LdapEntityMapping.java
@@ -0,0 +1,205 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.entities.mapping;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.environment.InvalidParameterException;
+import com.sun.apoc.spi.environment.MissingParameterException;
+import com.sun.apoc.spi.environment.RemoteEnvironmentException;
+import com.sun.apoc.spi.util.MetaConfiguration;
+
+/**
+ * Class for mapping LDAP identifiers for entities.
+ */
+public class LdapEntityMapping
+{
+ public static final String VALUE_SEPARATOR = "," ;
+ public static final String NAME_SEPARATOR = "/" ;
+
+ /** key to Organization information in MetaConfiguration */
+ private static final String ORG_KEY = "Organization/";
+ /** key to Domain information in MetaConfiguration */
+ private static final String DOMAIN_KEY = "Domain/";
+ /** key to User information in MetaConfiguration */
+ private static final String USER_KEY = "User/";
+ /** key to Host information in MetaConfiguration */
+ private static final String HOST_KEY = "Host/";
+ /** key to role information in MetaConfiguration */
+ private static final String ROLE_KEY = "Role/";
+
+ public static final String OBJCLASS = "ObjectClass" ;
+ public static final String NAMING_ATTR = "NamingAttribute" ;
+ public static final String CONTAINER = "Container" ;
+ public static final String UNIQUE_ATTR = "UniqueIdAttribute" ;
+ public static final String MEMBER_ATTR = "MemberAttribute" ;
+ public static final String LISTING_ATTR = "VirtualMemberAttribute" ;
+ public static final String DISPLAY = "DisplayNameFormat" ;
+
+ public ContainerMapping mOrganizationMapping = null;
+ public ContainerMapping mDomainMapping = null;
+ public ListMapping mRoleMapping = null;
+ public UserMapping mUserMapping = null;
+ public ItemMapping mHostMapping = null;
+
+ public LdapEntityMapping(MetaConfiguration aMetaConf)
+ throws SPIException {
+ mOrganizationMapping = new ContainerMapping(ORG_KEY, aMetaConf);
+ mDomainMapping = new ContainerMapping(DOMAIN_KEY, aMetaConf);
+ mRoleMapping = new ListMapping(ROLE_KEY, aMetaConf);
+ mUserMapping = new UserMapping(USER_KEY, aMetaConf);
+ mHostMapping = new ItemMapping(HOST_KEY, aMetaConf);
+ }
+
+ public static class ContainerMapping {
+ String [] mObjectClasses;
+ String [] mNamingAttributes;
+
+ ContainerMapping(String aPrefix,
+ MetaConfiguration aMetaConf) throws SPIException {
+ mObjectClasses = aMetaConf.getStrings(aPrefix + OBJCLASS) ;
+ mNamingAttributes = aMetaConf.getStrings(aPrefix + NAMING_ATTR) ;
+ if (mObjectClasses == null) {
+ throw new MissingParameterException(aPrefix + OBJCLASS);
+ }
+ if (mNamingAttributes == null) {
+ throw new MissingParameterException(aPrefix + NAMING_ATTR);
+ }
+ if (mObjectClasses.length != mNamingAttributes.length) {
+ StringBuffer paramValue = new StringBuffer();
+ for (int i=0 ; i<mNamingAttributes.length ; i++) {
+ paramValue.append(mNamingAttributes[i]);
+ }
+ throw new InvalidParameterException(
+ aPrefix + NAMING_ATTR, paramValue.toString());
+ }
+ }
+ public String[] getObjectClasses() { return mObjectClasses; }
+ public String[] getNamingAttributes() { return mNamingAttributes; }
+ }
+
+ public static class ListMapping extends ContainerMapping {
+ String mMemberAttribute;
+ String mListingAttribute;
+ String mContainerEntry;
+
+ ListMapping(String aPrefix, MetaConfiguration aMetaConf) throws SPIException {
+ super(aPrefix, aMetaConf) ;
+ mMemberAttribute = aMetaConf.getString(aPrefix + MEMBER_ATTR) ;
+ mListingAttribute = aMetaConf.getString(aPrefix + LISTING_ATTR) ;
+ if (mMemberAttribute == null) {
+ throw new MissingParameterException(aPrefix + MEMBER_ATTR);
+ }
+ if (mListingAttribute == null) {
+ throw new MissingParameterException(aPrefix + LISTING_ATTR);
+ }
+ mContainerEntry = aMetaConf.getString(aPrefix + CONTAINER) ;
+ if (mContainerEntry != null && mContainerEntry.length() == 0) {
+ mContainerEntry = null ;
+ }
+ }
+ public String getContainerEntry() { return mContainerEntry; }
+ public String getMemberAttribute() { return mMemberAttribute; }
+ public String getListingAttribute() { return mListingAttribute; }
+ }
+
+ public static class ItemMapping {
+
+ String mObjectClass = null ;
+ String mUniqueAttribute = null ;
+ String mContainerEntry = null ;
+
+ ItemMapping(String aPrefix, MetaConfiguration aMetaConf) throws SPIException {
+ mObjectClass = aMetaConf.getString(aPrefix + OBJCLASS) ;
+ mUniqueAttribute = aMetaConf.getString(aPrefix + UNIQUE_ATTR) ;
+ if (mObjectClass == null) {
+ throw new MissingParameterException(aPrefix + OBJCLASS);
+ }
+ if (mUniqueAttribute == null) {
+ throw new MissingParameterException(aPrefix + UNIQUE_ATTR);
+ }
+ mContainerEntry = aMetaConf.getString(aPrefix + CONTAINER) ;
+ if (mContainerEntry != null && mContainerEntry.length() == 0) {
+ mContainerEntry = null ;
+ }
+ }
+ public String getObjectClass() { return mObjectClass; }
+ public String getUniqueAttribute() { return mUniqueAttribute; }
+ public String getContainerEntry() { return mContainerEntry; }
+ }
+
+ public static class UserMapping extends ItemMapping {
+ String mDisplayFormat = null ;
+ String [] mDisplayAttributes = null ;
+ String []mSearchAttributes = null;
+ static final String DEFAULT_DISPLAY_FORMAT = "sn, givenname";
+
+ UserMapping(String aPrefix, MetaConfiguration aMetaConf)
+ throws SPIException {
+ super(aPrefix, aMetaConf) ;
+
+ mDisplayFormat = aMetaConf.getString(aPrefix + DISPLAY) ;
+ if (mDisplayFormat == null || mDisplayFormat.length() == 0) {
+ mDisplayFormat = DEFAULT_DISPLAY_FORMAT ;
+ }
+ StringTokenizer tokens = new StringTokenizer(mDisplayFormat, ",") ;
+ int i = 0 ;
+ mDisplayAttributes = new String [tokens.countTokens()] ;
+ while (tokens.hasMoreTokens()) {
+ mDisplayAttributes [i ++] = tokens.nextToken().trim() ;
+ }
+ }
+
+ public String getDisplayFormat() {
+ return mDisplayFormat;
+ }
+
+ public String[] getDisplayAttributes() {
+ return mDisplayAttributes;
+ }
+
+ public String[] getSearchAttributes() {
+ if (mSearchAttributes == null) {
+ mSearchAttributes = new String[1];
+ mSearchAttributes[0] = mUniqueAttribute ;
+ }
+ return mSearchAttributes;
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/environment/LdapConfigurationProvider.java b/src/com/sun/apoc/spi/ldap/environment/LdapConfigurationProvider.java
new file mode 100644
index 0000000..8209397
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/environment/LdapConfigurationProvider.java
@@ -0,0 +1,165 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.environment;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+import netscape.ldap.LDAPException;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.environment.ConfigurationProvider;
+import com.sun.apoc.spi.environment.RemoteEnvironmentException;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+
+/**
+ *
+ */
+public class LdapConfigurationProvider implements ConfigurationProvider {
+
+ // static Map url-properties to avoid connecting to Ldap server
+ // multiple times for the same url, therefore, same data
+ private static Map mContentMap = null;
+
+ private String mUrl = null;
+ private LdapClientContext mContext = null;
+ private LdapDataStore mDataStore = null;
+ private String[] mAttributesToGet = null;
+
+ /**
+ * Constructor
+ *
+ * @param context connection to the Ldap server
+ * @param dataStore datastore providing access
+ * to the Ldap server
+ * @param attributesToGet attributes to read data from,
+ * under the service entry of the Ldap server
+ */
+ public LdapConfigurationProvider(String url,
+ LdapClientContext context,
+ LdapDataStore dataStore,
+ String[] attributesToGet) {
+ if (mContentMap == null) {
+ mContentMap = new HashMap();
+ }
+ mUrl = url;
+ mContext = context;
+ mDataStore = dataStore;
+ mAttributesToGet = attributesToGet;
+ }
+
+ /**
+ * Loads the configuration data from the different attributes
+ * and put them all in the same Hashtable returned
+ *
+ * @return the Hashtable containing all the parameters
+ * read from the different attributes
+ * @throws SPIException if error occurs
+ * @see com.sun.apoc.spi.environment.ConfigurationProvider#loadData()
+ */
+ public Hashtable loadData() throws SPIException {
+ Properties propertyList = null;
+ synchronized (mContentMap) {
+ propertyList = (Properties) mContentMap.get(mUrl);
+ }
+ //Properties propertyList = null;
+ if (propertyList == null) {
+ Vector settings = null;
+ String [] attributes = {LdapDataStore.KEYVALUE_ATTR};
+ try {
+ settings = mDataStore.getAttributeValueList(
+ mDataStore.getRootServiceEntryDN(),
+ attributes, mContext);
+ } catch (LDAPException ldape) {
+ throw new RemoteEnvironmentException(
+ RemoteEnvironmentException.LDAP_CONF_KEY,
+ new String[] {mContext.getConnectionURL()}, ldape);
+ }
+ StringBuffer data = new StringBuffer();
+ for (int i=0; i<mAttributesToGet.length; i++) {
+ data.append(loadAttributeData(mAttributesToGet[i], settings));
+ }
+ ByteArrayInputStream input = new ByteArrayInputStream(
+ data.toString().getBytes());
+ propertyList = new Properties();
+ try {
+ propertyList.load(input);
+ } catch (IOException ioe) {
+ throw new RemoteEnvironmentException(
+ RemoteEnvironmentException.LDAP_CONF_KEY,
+ new String[] {mContext.getConnectionURL()}, ioe);
+ }
+ synchronized (mContentMap) {
+ mContentMap.put(mUrl, propertyList);
+ }
+ }
+ return propertyList;
+ }
+
+ /**
+ * Loads the configuration data from the specified attribute
+ * and return a StringBuffer containing the data
+ *
+ * @param attributeName attribute to read data from on the Ldap server
+ * @param settings settings for the Ldap server
+ * @return StringBuffer containing the data
+ * read in the attribute
+ * @throws RemoteEnvironmentException if data has incorrect format
+ */
+ private StringBuffer loadAttributeData(String attributeName,
+ Vector settings)
+ throws RemoteEnvironmentException {
+ StringBuffer data = new StringBuffer();
+ String [] values = LdapDataStore.getValuesForKey(settings, attributeName);
+ for (int i = 0; i < values.length; i++) {
+ String line = values[i];
+ if (data != null) {
+ data.append(line).append("\n");
+ } else {
+ throw new RemoteEnvironmentException(
+ RemoteEnvironmentException.INVALID_LDAP_CONF_KEY,
+ new String[] {mContext.getConnectionURL()});
+ }
+ }
+ return data;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/ldap/environment/LdapEnvironmentMgr.java b/src/com/sun/apoc/spi/ldap/environment/LdapEnvironmentMgr.java
new file mode 100644
index 0000000..24e9044
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/environment/LdapEnvironmentMgr.java
@@ -0,0 +1,627 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.environment;
+
+import java.util.Hashtable;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.environment.EnvironmentMgr;
+import com.sun.apoc.spi.environment.InvalidParameterException;
+import com.sun.apoc.spi.environment.MissingParameterException;
+import com.sun.apoc.spi.ldap.LdapClientContext;
+
+/**
+ * Handles the LDAP specific environmental information.
+ */
+public class LdapEnvironmentMgr extends EnvironmentMgr {
+
+ /** minimum port number allowed */
+ private final static int MINPORTNUMBER = 0;
+ /** maximum port number allowed */
+ private final static int MAXPORTNUMBER = 65535;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aEnvironment table of environmental information
+ */
+ public LdapEnvironmentMgr(Hashtable aEnvironment) {
+ super(aEnvironment);
+ }
+
+ private void checkURL(String url, String provider) throws SPIException {
+ if (getProtocolFromURL(url).equals(EnvironmentConstants.LDAP_URL_PROTOCOL)) {
+ int port = getPortFromURL(url);
+ if (port < MINPORTNUMBER || port > MAXPORTNUMBER) {
+ throw new InvalidParameterException(
+ provider+" "+EnvironmentConstants.URL_KEY+"#port",
+ String.valueOf(port),
+ "["+MINPORTNUMBER+","+MAXPORTNUMBER+"]");
+ }
+ if (getBaseEntryFromURL(url) == null) {
+ throw new MissingParameterException(
+ provider+" "+EnvironmentConstants.URL_KEY+"#BaseDN");
+ }
+ }
+ }
+
+ /**
+ * Check the validity of the configuration data provided in the
+ * environment table.
+ *
+ * @throws SPIException if data missing
+ * or value not appropriate
+ * @throws MissingParameterException
+ * @throws InvalidParameterException
+ */
+ public void checkEnvironment() throws SPIException {
+ // Organization
+ String[] orgURLs = getOrganizationURLs();
+ for (int i=0; i<orgURLs.length; i++) {
+ checkURL(orgURLs[i], "organization");
+ String user = getOrganizationUser(orgURLs[i]);
+ boolean noUser = (user == null) || (user.length() == 0);
+ char[] pwd = getOrganizationCredentials();
+ boolean noPwd = (pwd == null) || (pwd.length == 0);
+ if (noPwd && !noUser) {
+ throw new MissingParameterException(
+ "organization "+EnvironmentConstants.CREDENTIALS_KEY);
+ }
+ }
+ String authType = getOrganizationAuthType();
+ if (!authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS)
+ && !authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI)) {
+ throw new InvalidParameterException(
+ "organization "
+ +EnvironmentConstants.LDAP_AUTH_TYPE_KEY,
+ authType,
+ "{"+EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS
+ +","+EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI+"}");
+ }
+ // Domain
+ String[] domURLs = getDomainURLs();
+ for (int i=0; i<domURLs.length; i++) {
+ checkURL(domURLs[i], "domain");
+ String user = getDomainUser(domURLs[i]);
+ boolean noUser = (user == null) || (user.length() == 0);
+ char[] pwd = getDomainCredentials();
+ boolean noPwd = (pwd == null) || (pwd.length == 0);
+ if (noPwd && !noUser) {
+ throw new MissingParameterException(
+ "domain "+EnvironmentConstants.CREDENTIALS_KEY);
+ }
+ }
+ authType = getDomainAuthType();
+ if (!authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS)
+ && !authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI)) {
+ throw new InvalidParameterException(
+ "domain "
+ +EnvironmentConstants.LDAP_AUTH_TYPE_KEY,
+ authType,
+ "{"+EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS
+ +","+EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI+"}");
+ }
+ // Profile
+ String[] profileURLs = getProfileURLs();
+ for (int i=0; i<profileURLs.length; i++) {
+ checkURL(profileURLs[i], "profile");
+ String user = getProfileUser(profileURLs[i]);
+ boolean noUser = (user == null) || (user.length() == 0);
+ char[] pwd = getProfileCredentials();
+ boolean noPwd = (pwd == null) || (pwd.length == 0);
+ if (noPwd && !noUser) {
+ throw new MissingParameterException(
+ "profile "+EnvironmentConstants.CREDENTIALS_KEY);
+ }
+ }
+ authType = getProfileAuthType();
+ if (!authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS)
+ && !authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI)) {
+ throw new InvalidParameterException(
+ "profile "
+ +EnvironmentConstants.LDAP_AUTH_TYPE_KEY,
+ authType,
+ "{"+EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS
+ +","+EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI+"}");
+ }
+ // Assignment
+ String[] assignmentURLs = getAssignmentURLs();
+ for (int i=0; i<assignmentURLs.length; i++) {
+ checkURL(assignmentURLs[i], "assignment");
+ String user = getAssignmentUser(assignmentURLs[i]);
+ boolean noUser = (user == null) || (user.length() == 0);
+ char[] pwd = getAssignmentCredentials();
+ boolean noPwd = (pwd == null) || (pwd.length == 0);
+ if (noPwd && !noUser) {
+ throw new MissingParameterException(
+ "assignment "+EnvironmentConstants.CREDENTIALS_KEY);
+ }
+ }
+ authType = getAssignmentAuthType();
+ if (!authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS)
+ && !authType.equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI)) {
+ throw new InvalidParameterException(
+ "assignment "
+ +EnvironmentConstants.LDAP_AUTH_TYPE_KEY,
+ authType,
+ "{"+EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS
+ +","+EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI+"}");
+ }
+ // Metaconfiguration
+ String[] metaconfURLs = getMetaConfURLs();
+ for (int i=0; i<metaconfURLs.length; i++) {
+ checkURL(metaconfURLs[i], "metaconfiguration");
+ }
+ }
+
+ /**
+ * gets the value of the host from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the host extracted from the URL
+ * or localhost si error or one does not exists
+ */
+ public static String getHostFromURL(String stringURL) {
+ String host = EnvironmentMgr.getHostFromURL(stringURL);
+ if ((host == null) || (host.equals(""))) {
+ host = EnvironmentConstants.LDAP_DEFAULT_SERVER;
+ }
+ return host;
+ }
+
+ /**
+ * gets the value of the port from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the port extracted from the URL
+ * or 389 si error or one does not exists
+ */
+ public static int getPortFromURL(String stringURL) {
+ int port = EnvironmentMgr.getPortFromURL(stringURL);
+ if (port < 0) {
+ port = EnvironmentConstants.LDAP_DEFAULT_PORT;
+ }
+ return port;
+ }
+
+ /**
+ * Accessor for the metaconfiguration.
+ *
+ * @return the metaconfiguration object
+ */
+ public Hashtable getMetaConfiguration() {
+ return (Hashtable)mEnvironment.get(
+ EnvironmentConstants.LDAP_URL_PROTOCOL);
+ }
+
+ /**
+ * Accessor for the authorized user name applicable
+ * to the organization datasource
+ *
+ * @return the authorized user name
+ * for the organization datasource
+ * or anonymous if not found
+ */
+ public String getOrganizationAuthUser() {
+ String user = getParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_USER_KEY);
+ if (user == null) {
+ user = EnvironmentConstants.LDAP_USER_ANONYMOUS;
+ }
+ return user;
+ }
+
+ /**
+ * Accessor for the authorized user name applicable
+ * to the domain datasource
+ *
+ * @return the authorized user name
+ * for the domain datasource
+ * or anonymous if not found
+ */
+ public String getDomainAuthUser() {
+ String user = getParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_USER_KEY);
+ if (user == null) {
+ user = EnvironmentConstants.LDAP_USER_ANONYMOUS;
+ }
+ return user;
+ }
+
+ /**
+ * Accessor for the authorized user name applicable
+ * to the profile datasource
+ *
+ * @return the authorized user name
+ * for the profile datasource
+ * or anonymous if not found
+ */
+ public String getProfileAuthUser() {
+ String user = getParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_USER_KEY);
+ if (user == null) {
+ user = EnvironmentConstants.LDAP_USER_ANONYMOUS;
+ }
+ return user;
+ }
+
+ /**
+ * Accessor for the authorized user name applicable
+ * to the assignment datasource
+ *
+ * @return the authorized user name
+ * for the assignment datasource
+ * or anonymous if not found
+ */
+ public String getAssignmentAuthUser() {
+ String user = getParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_USER_KEY);
+ if (user == null) {
+ user = EnvironmentConstants.LDAP_USER_ANONYMOUS;
+ }
+ return user;
+ }
+
+ /**
+ * Accessor for the authorized user name applicable
+ * to the metaconfiguration datasource
+ *
+ * @return the authorized user name
+ * for the metaconfiguration datasource
+ * or anonymous if not found
+ */
+ public String getMetaConfAuthUser() {
+ String user = getParam(EnvironmentConstants.LDAP_META_CONF_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_USER_KEY);
+ if (user == null) {
+ user = EnvironmentConstants.LDAP_USER_ANONYMOUS;
+ }
+ return user;
+ }
+
+ /**
+ * Accessor for the authorized password applicable
+ * to the organization datasource
+ *
+ * @return the authorized password
+ * for the organization datasource
+ */
+ public char[] getOrganizationAuthPassword() {
+ return getPasswordParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_PASSWORD_KEY);
+ }
+
+ /**
+ * Accessor for the authorized password applicable
+ * to the domain datasource
+ *
+ * @return the authorized password
+ * for the domain datasource
+ */
+ public char[] getDomainAuthPassword() {
+ return getPasswordParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_PASSWORD_KEY);
+ }
+
+ /**
+ * Accessor for the authorized password applicable
+ * to the profile datasource
+ *
+ * @return the authorized password
+ * for the profile datasource
+ */
+ public char[] getProfileAuthPassword() {
+ return getPasswordParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_PASSWORD_KEY);
+ }
+
+ /**
+ * Accessor for the authorized password applicable
+ * to the assignment datasource
+ *
+ * @return the authorized password
+ * for the assignment datasource
+ */
+ public char[] getAssignmentAuthPassword() {
+ return getPasswordParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_PASSWORD_KEY);
+ }
+
+ /**
+ * Accessor for the authorized password applicable
+ * to the metaconfiguration datasource
+ *
+ * @return the authorized password
+ * for the metaconfiguration datasource
+ */
+ public char[] getMetaConfAuthPassword() {
+ return getPasswordParam(EnvironmentConstants.LDAP_META_CONF_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_PASSWORD_KEY);
+ }
+
+ /**
+ * Accessor for the authentication type applicable
+ * to the organization datasource
+ *
+ * @return the authentication type
+ * for the organization datasource
+ */
+ public String getOrganizationAuthType() {
+ String param = getParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_TYPE_KEY);
+ if ( (param == null) || (param.length() == 0) ) {
+ param = EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS;
+ }
+ return param;
+ }
+
+ /**
+ * Accessor for the authentication type applicable
+ * to the domain datasource
+ *
+ * @return the authentication type
+ * for the domain datasource
+ */
+ public String getDomainAuthType() {
+ String param = getParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_TYPE_KEY);
+ if ( (param == null) || (param.length() == 0) ) {
+ param = EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS;
+ }
+ return param;
+ }
+
+ /**
+ * Accessor for the authentication type applicable
+ * to the profile datasource
+ *
+ * @return the authentication type
+ * for the profile datasource
+ */
+ public String getProfileAuthType() {
+ String param = getParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_TYPE_KEY);
+ if ( (param == null) || (param.length() == 0) ) {
+ param = EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS;
+ }
+ return param;
+ }
+
+ /**
+ * Accessor for the authentication type applicable
+ * to the assignment datasource
+ *
+ * @return the authentication type
+ * for the assignment datasource
+ */
+ public String getAssignmentAuthType() {
+ String param = getParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.LDAP_AUTH_TYPE_KEY);
+ if ( (param == null) || (param.length() == 0) ) {
+ param = EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS;
+ }
+ return param;
+ }
+
+ /**
+ * Accessor for the connection timeout applicable
+ * to the organization datasource
+ *
+ * @return the connection timeout
+ * for the organization datasource
+ */
+ public int getOrganizationTimeout() {
+ String param = getParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.LDAP_TIMEOUT_KEY);
+ return getIntParamFromString(param,
+ EnvironmentConstants.LDAP_DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * Accessor for the connection timeout applicable
+ * to the domain datasource
+ *
+ * @return the connection timeout
+ * for the domain datasource
+ */
+ public int getDomainTimeout() {
+ String param = getParam(EnvironmentConstants.DOMAIN_PREFIX,
+ EnvironmentConstants.LDAP_TIMEOUT_KEY);
+ return getIntParamFromString(param,
+ EnvironmentConstants.LDAP_DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * Accessor for the connection timeout applicable
+ * to the assignment datasource
+ *
+ * @return the connection timeout
+ * for the assignment datasource
+ */
+ public int getAssignmentTimeout() {
+ String param = getParam(EnvironmentConstants.ASSIGNMENT_PREFIX,
+ EnvironmentConstants.LDAP_TIMEOUT_KEY);
+ return getIntParamFromString(param,
+ EnvironmentConstants.LDAP_DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * Accessor for the connection timeout applicable
+ * to the profile datasource
+ *
+ * @return the connection timeout
+ * for the profile datasource
+ */
+ public int getProfileTimeout() {
+ String param = getParam(EnvironmentConstants.PROFILE_PREFIX,
+ EnvironmentConstants.LDAP_TIMEOUT_KEY);
+ return getIntParamFromString(param,
+ EnvironmentConstants.LDAP_DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * Accessor for the connection timeout applicable
+ * to the metaconfiguration datasource
+ *
+ * @return the connection timeout
+ * for the metaconfiguration datasource
+ */
+ public int getMetaConfTimeout() {
+ String param = getParam(EnvironmentConstants.LDAP_META_CONF_PREFIX,
+ EnvironmentConstants.LDAP_TIMEOUT_KEY);
+ return getIntParamFromString(param,
+ EnvironmentConstants.LDAP_DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * gets the value the LDAP Base Entry from a URL parameter
+ *
+ * @param stringURL the string representing the URL
+ * @return the base entry extracted from the URL
+ * or empty string if one does not exist
+ */
+ public static String getBaseEntryFromURL(String url) {
+ String baseEntry = null;
+ baseEntry = getPathFromURL(url);
+ if (baseEntry != null) {
+ if (baseEntry.startsWith(EnvironmentConstants.URL_SEPARATOR)) {
+ baseEntry = baseEntry.substring(1);
+ }
+ }
+ return baseEntry;
+ }
+
+ /**
+ * Accessor for the URL applicable
+ * to the metaconfiguration datasource
+ *
+ * @return the URL for the metaconfiguration datasource
+ */
+ public String[] getMetaConfURLs() {
+ String urls = getParam(EnvironmentConstants.LDAP_META_CONF_PREFIX,
+ EnvironmentConstants.URL_KEY);
+
+ // It's assumed that if there's no explicit mention of the meta-conf
+ // provider, the organisation entity provider is the winner.
+ if (urls == null || urls.length() == 0) {
+ urls = getParam(EnvironmentConstants.ORGANIZATION_PREFIX,
+ EnvironmentConstants.URL_KEY) ;
+ }
+ return getURLList(urls);
+ }
+
+ /**
+ * Accessor for the authentication callback handler applicable
+ * to the organization datasource
+ *
+ * @return the callback handler object
+ * for the organization datasource
+ */
+ public Object getOrganizationCallbackHandler() {
+ Object cbh = null;
+ cbh = mEnvironment.get(
+ EnvironmentConstants.ORGANIZATION_PREFIX
+ +EnvironmentConstants.LDAP_AUTH_CBH);
+ if (cbh == null) {
+ cbh = mEnvironment.get(EnvironmentConstants.LDAP_AUTH_CBH);
+ }
+ return cbh;
+ }
+
+ /**
+ * Accessor for the authentication callback handler applicable
+ * to the domain datasource
+ *
+ * @return the callback handler object
+ * for the domain datasource
+ */
+ public Object getDomainCallbackHandler() {
+ Object cbh = null;
+ cbh = mEnvironment.get(
+ EnvironmentConstants.DOMAIN_PREFIX
+ +EnvironmentConstants.LDAP_AUTH_CBH);
+ if (cbh == null) {
+ cbh = mEnvironment.get(EnvironmentConstants.LDAP_AUTH_CBH);
+ }
+ return cbh;
+ }
+
+ /**
+ * Accessor for the authentication callback handler applicable
+ * to the profile datasource
+ *
+ * @return the callback handler object
+ * for the profile datasource
+ */
+ public Object getProfileCallbackHandler() {
+ Object cbh = null;
+ cbh = mEnvironment.get(
+ EnvironmentConstants.PROFILE_PREFIX
+ +EnvironmentConstants.LDAP_AUTH_CBH);
+ if (cbh == null) {
+ cbh = mEnvironment.get(EnvironmentConstants.LDAP_AUTH_CBH);
+ }
+ return cbh;
+ }
+
+ /**
+ * Accessor for the authentication callback handler applicable
+ * to the assignment datasource
+ *
+ * @return the callback handler object
+ * for the assignment datasource
+ */
+ public Object getAssignmentCallbackHandler() {
+ Object cbh = null;
+ cbh = mEnvironment.get(
+ EnvironmentConstants.ASSIGNMENT_PREFIX
+ +EnvironmentConstants.LDAP_AUTH_CBH);
+ if (cbh == null) {
+ cbh = mEnvironment.get(EnvironmentConstants.LDAP_AUTH_CBH);
+ }
+ return cbh;
+ }
+
+ /**
+ * Accessor fot the Max Search Results parameter
+ * @return the value of the parameter for max search results
+ */
+ public int getSearchResultSizeLimit() {
+ String stSize = this.getStringParam(EnvironmentConstants.MAX_SEARCH_RESULTS);
+ int size = this.getIntParamFromString(stSize, LdapClientContext.DEFAULT_MAX_SEARCH_RESULTS);
+ return size;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/policies/LdapPolicy.java b/src/com/sun/apoc/spi/ldap/policies/LdapPolicy.java
new file mode 100644
index 0000000..a95f1dc
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/policies/LdapPolicy.java
@@ -0,0 +1,167 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.policies;
+
+import java.util.ArrayList;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.ldap.entities.LdapEntity;
+import com.sun.apoc.spi.ldap.util.Timestamp;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileImpl;
+
+/**
+ * Class for a policy.
+ *
+ */
+public class LdapPolicy extends Policy {
+ protected String mLocation;
+ protected ProfileImpl mProfile;
+ protected Entity mAuthor;
+
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aProfile profile object
+ * @param aData data stored
+ */
+ public LdapPolicy(String aId, String aData, String aLocation,
+ ProfileImpl aProfile) {
+ super(aId, aProfile.getId(), aData);
+ mProfile = aProfile;
+ mLocation = aLocation;
+ }
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aProfile profile object
+ * @param aData data stored
+ */
+ public LdapPolicy(String aId, String aData, long aLastModified,
+ String aLocation, ProfileImpl aProfile) {
+ super(aId, aProfile.getId(), aData, aLastModified);
+ mProfile = aProfile;
+ mLocation = aLocation;
+ }
+
+ /**
+ * Returns the location for this policy.
+ *
+ * @return location for the policy
+ */
+ public String getLocation() { return mLocation; }
+
+ /**
+ * Sets the location for this policy.
+ *
+ * @param aLocation location for the policy
+ */
+ public void setLocation(String aLocation) {
+ mLocation = aLocation;
+ }
+
+ /**
+ * Sets the data XMLBlob for the policy object.
+ *
+ * @param policy data
+ */
+ public void setData(String aData) {
+ mData = aData;
+ }
+
+ /**
+ * Returns the profile to which this policy belongs.
+ *
+ * @return profile
+ */
+ public Profile getProfile() { return mProfile; }
+
+ /**
+ * Sets the author for the last modification of this policy.
+ *
+ * @param aAuthor entity that last modified this policy
+ */
+ public void setAuthor(Entity aAuthor) {
+ mAuthor = aAuthor;
+ }
+
+ /**
+ * Returns the author of the most recent modification
+ * of this policy.
+ *
+ * @return author of the last modification
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getAuthor() throws SPIException {
+ if (mAuthor == null) {
+ LdapEntity entity =
+ (LdapEntity)getProfile().getProfileRepository().getEntity();
+ ArrayList retValues = entity.getDataStore()
+ .getModificationDetails(this);
+ setLastModified((String)retValues.get(0));
+ if (retValues.size() > 1) {
+ mAuthor = (Entity)retValues.get(1);
+ }
+ }
+ return mAuthor;
+ }
+
+ /**
+ * Sets the time in milliseconds for the last
+ * modification of the policy.
+ *
+ * @param aLastModified the String value for the modification
+ * time as returned by the database
+ */
+ public void setLastModified(String aLastModified) {
+ mLastModified = Timestamp.getMillis(aLastModified);
+ }
+
+ /**
+ * Sets the id for the policy.
+ *
+ * @param aId the id
+ */
+ public void setId(String aId) {
+ mId = aId;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/profiles/LdapProfile.java b/src/com/sun/apoc/spi/ldap/profiles/LdapProfile.java
new file mode 100644
index 0000000..aaa4c2f
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/profiles/LdapProfile.java
@@ -0,0 +1,545 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.profiles;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Vector;
+
+import netscape.ldap.LDAPDN;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.LdapEntity;
+import com.sun.apoc.spi.ldap.policies.LdapPolicy;
+import com.sun.apoc.spi.ldap.util.Timestamp;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.InvalidDisplayNameException;
+import com.sun.apoc.spi.profiles.ProfileImpl;
+import com.sun.apoc.spi.profiles.ProfileRepositoryImpl;
+import com.sun.apoc.spi.profiles.UnknownApplicabilityException;
+
+/**
+ * Implementation for an LDAP profile.
+ *
+ */
+public class LdapProfile extends ProfileImpl
+{
+ private static final String DEFAULT_DISPLAY_NAME = "Settings for ";
+ private String mLocation;
+ private long mLastModified = 0;
+ private Entity mAuthor;
+
+ /**
+ * Constructor.
+ *
+ * @param aId id
+ * @param aRepository <code>ProfileRepository</code> object
+ * @param aDisplayName display name
+ * @param aApplicability scope for the profile
+ * @param aPriority priority
+ */
+ public LdapProfile(String aId, ProfileRepositoryImpl aRepository,
+ String aDisplayName, Applicability aApplicability,
+ int aPriority) {
+ super(aId, aRepository, aDisplayName, aApplicability, aPriority);
+ mLocation = aId;
+ }
+
+ /**
+ * Returns the display name for this profile.
+ *
+ * @return display name for this profile
+ */
+ public String getDisplayName() {
+ if ( (mDisplayName == null) || (mDisplayName.length() == 0)
+ || (mDisplayName.equals(LdapProfileRepository.DEFAULT_HOST_PROFILE_NAME))
+ || (mDisplayName.equals(LdapProfileRepository.DEFAULT_USER_PROFILE_NAME)) ) {
+ String entityName = "";
+ try {
+ entityName =
+ getProfileRepository().getEntity().getDisplayName(null);
+ }
+ catch (SPIException ignore) {}
+ return DEFAULT_DISPLAY_NAME + entityName;
+ }
+ return mDisplayName;
+ }
+
+ /**
+ * Sets the priority for this profile.
+ *
+ * @param aPriority priority for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setPriority(int aPriority)
+ throws SPIException {
+ if (this.isLocal()) {
+ LdapProfileRepository rep = (LdapProfileRepository)
+ this.getProfileRepository();
+ rep.migrateProfile(this);
+ }
+ ((LdapEntity)getProfileRepository().getEntity()).getDataStore()
+ .setProfilePriority(this, aPriority);
+ mPriority = aPriority;
+ }
+
+ /**
+ * Sets the display name for this profile.
+ *
+ * @param aDisplayName new display name for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setDisplayName(String aDisplayName)
+ throws SPIException {
+ if ((aDisplayName == null) || (aDisplayName.length() == 0)) {
+ throw new InvalidDisplayNameException();
+ }
+ ((LdapEntity)getProfileRepository().getEntity()).getDataStore()
+ .setProfileDisplayName(this, aDisplayName);
+ mDisplayName = aDisplayName;
+ }
+
+ /**
+ * Sets the comment for this profile. If the new
+ * comment is null then the existing comment is removed.
+ *
+ * @param aComment comment as a String
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setComment(String aComment)
+ throws SPIException {
+ if (aComment == null) {
+ throw new IllegalArgumentException();
+ }
+ ((LdapEntity)getProfileRepository().getEntity()).getDataStore()
+ .setProfileComment(this, aComment);
+ mComment = aComment;
+ if (aComment == null) { mNoCommentFound = true; }
+ }
+
+ /**
+ * Sets the scope for this profile.
+ *
+ * @param aApplicability new scope for this profile
+ * @throws UnknownApplicabilityException if applicability unknown
+ * @throws SPIException if error occurs
+ */
+ public void setApplicability(Applicability aApplicability)
+ throws SPIException {
+ if (aApplicability == null) {
+ throw new IllegalArgumentException();
+ }
+ if (mApplicability.equals(aApplicability)) {
+ return;
+ }
+ if (aApplicability.equals(Applicability.UNKNOWN)) {
+ throw new UnknownApplicabilityException();
+ }
+ if (this.isLocal()) {
+ LdapProfileRepository rep = (LdapProfileRepository)
+ this.getProfileRepository();
+ rep.migrateProfile(this);
+ }
+ ((LdapEntity)getProfileRepository().getEntity()).getDataStore()
+ .setProfileApplicability(this, aApplicability);
+ mApplicability = aApplicability;
+ }
+
+ /**
+ * Returns the datastore location.
+ *
+ * @return the location
+ */
+ public String getLocation() { return mLocation; }
+
+ /**
+ * Stores a <code>Policy</code>.
+ *
+ * @param aPolicy the policy to store
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void storePolicy(Policy aPolicy)
+ throws SPIException {
+ if (aPolicy == null) {
+ throw new IllegalArgumentException();
+ }
+ ((LdapEntity)getProfileRepository().getEntity()).getDataStore()
+ .storePolicy((ProfileImpl)this, aPolicy);
+ }
+
+ /**
+ * Destroys a <code>Policy</code>.
+ *
+ * @param aPolicy the policy object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void destroyPolicy(Policy aPolicy)
+ throws SPIException {
+ if (aPolicy == null) {
+ throw new IllegalArgumentException();
+ }
+ ((LdapEntity)getProfileRepository().getEntity()).getDataStore()
+ .destroyPolicy(aPolicy);
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this profile
+ * has policies.
+ *
+ * @return <code>true</code> if there are policies,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasPolicies() throws SPIException {
+ return ((LdapEntity)getProfileRepository().getEntity())
+ .getDataStore().hasPolicies(this);
+ }
+
+ /**
+ * Returns the policies for this profile.
+ *
+ * @return <code>Iterator</code> of all the policies for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicies()
+ throws SPIException {
+ mPolicies = ((LdapEntity)getProfileRepository().getEntity())
+ .getDataStore().getPolicies(this);
+ return mPolicies.iterator();
+ }
+
+ /**
+ * Returns the policies for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the policies
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicies(Iterator aPolicyIdList)
+ throws SPIException {
+ if (aPolicyIdList == null) {
+ throw new IllegalArgumentException();
+ }
+ return (((LdapEntity)getProfileRepository().getEntity())
+ .getDataStore().getPolicies(this, aPolicyIdList))
+ .iterator();
+ }
+
+ /**
+ * Returns the PolicyInfos for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the PolicyInfos
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicyInfos(Iterator aPolicyIdList)
+ throws SPIException {
+ if (aPolicyIdList == null) {
+ throw new IllegalArgumentException();
+ }
+ return (((LdapEntity)getProfileRepository().getEntity())
+ .getDataStore().getPolicyInfos(this, aPolicyIdList))
+ .iterator();
+ }
+
+ /**
+ * Returns the requested policy object.
+ *
+ * @param aId the id for the required policy
+ * @return the policy object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Policy getPolicy(String aId)
+ throws SPIException {
+ if (aId == null) {
+ throw new IllegalArgumentException();
+ }
+ return ((LdapEntity)getProfileRepository().getEntity())
+ .getDataStore().getPolicy(this, aId);
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this profile
+ * has been assigned to entities.
+ *
+ * @return <code>true</code> if there are entities,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasAssignedEntities() throws SPIException {
+ LdapDataStore dataStore =
+ ((LdapEntity)getProfileRepository().getEntity())
+ .getDataStore();
+ if (dataStore.isVersion1() && this.isLocal()) {
+ return true;
+ }
+ Vector entities = dataStore.getListOfEntitiesForProfile(this);
+ return ((entities!=null) && (!entities.isEmpty()));
+ }
+
+ /**
+ * Returns the entities to which this profile has been assigned.
+ *
+ * @return <code>Iterator</code> of entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getAssignedEntities()
+ throws SPIException {
+ PolicySource aPolicySource =
+ ((ProfileRepositoryImpl)getProfileRepository()).getPolicySource();
+ return aPolicySource.getAssignmentProvider()
+ .getAssignedEntities(this);
+ }
+
+ /**
+ * Returns the time in milliseconds of the most
+ * recent modification of the profile entry and
+ * its policies.
+ *
+ * @return time of the last modification in milliseconds
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public long getLastModified()
+ throws SPIException {
+ long lastModified = getLastModifiedForEntry();
+ getPolicies();
+ if (mPolicies != null) {
+ Iterator iterPolicies = mPolicies.iterator();
+ while (iterPolicies.hasNext()) {
+ Policy policy = (Policy)iterPolicies.next();
+ long modified = policy.getLastModified();
+ if (modified > lastModified) {
+ lastModified = modified;
+ }
+ }
+ }
+ return lastModified;
+ }
+
+ /**
+ * Returns the time in milliseconds of the most
+ * recent modification of the profile entry.
+ *
+ * @return time of the last modification in milliseconds
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private long getLastModifiedForEntry()
+ throws SPIException {
+ if (mLastModified == 0) {
+ LdapEntity entity =
+ (LdapEntity)getProfileRepository().getEntity();
+ ArrayList retValues = entity.getDataStore()
+ .getModificationDetails(this);
+ setLastModified((String)retValues.get(0));
+ if (retValues.size() > 1) {
+ mAuthor = (Entity)retValues.get(1);
+ }
+ }
+ return mLastModified;
+ }
+
+ /**
+ * Returns the author of the most recent modification
+ * of the profile.
+ *
+ * @return name of the author of the last modification
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getAuthor()
+ throws SPIException {
+ Entity author = null;
+ String authorName = new String("");
+ if (mPolicies == null) { getPolicies(); }
+ Iterator iterPolicies = mPolicies.iterator();
+ LdapPolicy lastModifiedPolicy = null;
+ long lastModified = 0;
+ while (iterPolicies.hasNext()) {
+ LdapPolicy policy = (LdapPolicy)iterPolicies.next();
+ long modified = policy.getLastModified();
+ if (modified > lastModified) {
+ lastModified = modified;
+ lastModifiedPolicy = policy;
+ }
+ }
+ if (getLastModifiedForEntry() >= lastModified) {
+ author = getAuthorForEntry();
+ }
+ else {
+ author = lastModifiedPolicy.getAuthor();
+ }
+ if (author != null) {
+ authorName = author.getDisplayName(null);
+ }
+ return authorName;
+ }
+
+ /**
+ * Returns the author of the most recent modification
+ * of the profile entry.
+ *
+ * @return author of the last modification
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getAuthorForEntry()
+ throws SPIException {
+ if (mAuthor == null) {
+ LdapEntity entity =
+ (LdapEntity)getProfileRepository().getEntity();
+ ArrayList retValues = entity.getDataStore()
+ .getModificationDetails(this);
+ setLastModified((String)retValues.get(0));
+ if (retValues.size() > 1) {
+ mAuthor = (Entity)retValues.get(1);
+ }
+ }
+ return mAuthor;
+ }
+
+ /**
+ * Sets the time in milliseconds for the last
+ * modification of the profile entry.
+ *
+ * @param aLastModified the String value for the modification
+ * time as returned by the database
+ */
+ public void setLastModified(String aLastModified) {
+ if (aLastModified == null) {
+ throw new IllegalArgumentException();
+ }
+ mLastModified = Timestamp.getMillis(aLastModified);
+ }
+
+ /**
+ * Returns the comment for this profile.
+ *
+ * @return comment
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getComment()
+ throws SPIException {
+ if (mComment == null && !mNoCommentFound) {
+ mComment = findComment();
+ }
+ if (mComment == null) {
+ return new String("");
+ }
+ return mComment;
+ }
+
+ /**
+ * Finds the comment for the profile.
+ *
+ * @return comment for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ private String findComment()
+ throws SPIException {
+ return ((LdapEntity)getProfileRepository().getEntity())
+ .getDataStore().getProfileComment(this);
+ }
+
+ /**
+ * Tests for equality with another Profile.
+ *
+ * @param aProfile other profile
+ * @return <code>true</code> if both profiles are
+ * equal, otherwise <code>false</code>
+ */
+ public boolean equals (Object aProfile) {
+ if (aProfile instanceof LdapProfile) {
+ return LDAPDN.equals(mLocation.toLowerCase(),
+ ((LdapProfile) aProfile).mLocation.toLowerCase()) ;
+ }
+ return false;
+ }
+
+ /**
+ * Test if the profile is a Local Profile
+ * ie. its DN contains _defaultuserpolicygroup_
+ * or _defaulthostpolicygroup_
+ *
+ * @return true if profile is local,
+ * otherwise false
+ */
+ public boolean isLocal() {
+ return isLocalProfileDN(this.getId());
+ }
+
+ /**
+ * Test if a DN is a Local Profile DN
+ * ie. it contains _defaultuserpolicygroup_
+ * or _defaulthostpolicygroup_
+ *
+ * @param dn dn to test
+ * @return true if dn is a Local Profile DN,
+ * otherwise false
+ */
+ public static boolean isLocalProfileDN (String dn) {
+ String hostStart = LdapDataStore.CONFIG_NAMING_ATTR
+ +LdapProfileRepository.DEFAULT_HOST_PROFILE_DN;
+ String userStart = LdapDataStore.CONFIG_NAMING_ATTR
+ +LdapProfileRepository.DEFAULT_USER_PROFILE_DN;
+ return (dn.startsWith(hostStart) || dn.startsWith(userStart));
+ }
+
+ /**
+ * copy each attribute from profile to the current
+ * Profile attributes
+ * Used to modify a LdapProfile passed as a parameter
+ * to a method.
+ *
+ * @param profile profile to copy into current profile
+ */
+ public void copy(LdapProfile profile) {
+ mLocation = profile.getLocation();
+ mLastModified = 0;
+ mAuthor = null;
+ mId = profile.getId();
+ mRepository = (ProfileRepositoryImpl)profile.getProfileRepository();
+ mDisplayName = profile.getDisplayName();
+ mApplicability = profile.getApplicability();
+ mPriority = profile.getPriority();
+ mComment = null;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/profiles/LdapProfileComparator.java b/src/com/sun/apoc/spi/ldap/profiles/LdapProfileComparator.java
new file mode 100644
index 0000000..80d80cb
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/profiles/LdapProfileComparator.java
@@ -0,0 +1,78 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.profiles;
+
+import java.util.Comparator;
+
+import netscape.ldap.LDAPDN;
+
+/**
+ * Compares two LdapProfiles according to their priority
+ *
+ */
+public class LdapProfileComparator implements Comparator {
+
+ /* (non-Javadoc)
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public int compare(Object aProfile1, Object aProfile2) {
+ LdapProfile profile1 = (LdapProfile) aProfile1 ;
+ LdapProfile profile2 = (LdapProfile) aProfile2 ;
+ if (profile1 == null) { return profile2 == null ? 0 : -1 ; }
+ if (profile2 == null) { return 1 ; }
+ String [] pg1DN = LDAPDN.explodeDN(
+ profile1.getProfileRepository().getId(), false) ;
+ int pg1Length = pg1DN.length;
+ String [] pg2DN = LDAPDN.explodeDN(
+ profile2.getProfileRepository().getId(), false) ;
+ int pg2Length = pg2DN.length;
+ if (pg1Length != pg2Length) {
+ return pg1Length - pg2Length;
+ }
+ // the lengths are equals,
+ // the 2 profiles ares defined in the same repository
+ // if one of the profiles is local, it wins
+ if (profile1.isLocal()) { return 1 ; }
+ if (profile2.isLocal()) { return -1 ; }
+ // 2 non-local profiles defined in the same repository
+ // are compared using their priority
+ if (profile1.getPriority() != profile2.getPriority()) {
+ return profile1.getPriority() - profile2.getPriority() ;
+ }
+ return profile1.getId().compareTo(
+ profile2.getId());
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/ldap/profiles/LdapProfileProvider.java b/src/com/sun/apoc/spi/ldap/profiles/LdapProfileProvider.java
new file mode 100644
index 0000000..08fa419
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/profiles/LdapProfileProvider.java
@@ -0,0 +1,204 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.profiles;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.environment.EnvironmentConstants;
+import com.sun.apoc.spi.ldap.LdapConnectionHandler;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.LdapEntity;
+import com.sun.apoc.spi.ldap.environment.LdapEnvironmentMgr;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileComparatorProvider;
+import com.sun.apoc.spi.profiles.ProfileProvider;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+/**
+ * Provides access to the profiles stored in a LDAP backend
+ *
+ */
+public class LdapProfileProvider
+ implements ProfileProvider, ProfileComparatorProvider {
+
+ protected PolicySource mPolicySource;
+ protected LdapConnectionHandler mConnection;
+ protected LdapDataStore mDataStore;
+ protected LdapEnvironmentMgr mEnvironmentMgr;
+ protected String mURL;
+
+ public LdapProfileProvider(PolicySource aPolicySource, String url)
+ throws SPIException {
+ mPolicySource = aPolicySource;
+ mEnvironmentMgr = new LdapEnvironmentMgr(mPolicySource.getEnvironment());
+ String mURL = url;
+ mConnection = (LdapConnectionHandler) mPolicySource.getConnectionHandler(mURL);
+ if (mConnection == null) {
+ // if mConnection is null, no Ldap connection has been
+ // established yet, the environment hasn't been checked
+ mEnvironmentMgr.checkEnvironment();
+ }
+ }
+
+ /**
+ * Returns a Comparator object used to order the Profiles
+ * @return a comparator to order Profiles
+ */
+ public Comparator getProfileComparator() {
+ return new LdapProfileComparator();
+ }
+
+ /**
+ * Opens the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws OpenConnectionException if connection error occurs
+ * @throws CloseConnectionException if connection error occurs
+ * @throws AuthenticateException if connection error occurs
+ */
+ public void open() throws SPIException {
+ if ((mConnection == null) && (mEnvironmentMgr != null)) {
+ mConnection = new LdapConnectionHandler();
+ mConnection.connect(mURL,
+ mEnvironmentMgr.getProfileTimeout(),
+ mEnvironmentMgr.getProfileAuthUser(),
+ mEnvironmentMgr.getProfileAuthPassword(),
+ mEnvironmentMgr);
+ if (isGSSAPIAuthentication()){
+ Object callbackHandler =
+ mEnvironmentMgr.getProfileCallbackHandler();
+ mConnection.authenticate(callbackHandler);
+ }
+ else {
+ mConnection.authenticate(mEnvironmentMgr.getProfileUser(mURL),
+ mEnvironmentMgr.getProfileCredentials());
+ }
+ mConnection.closeAuthorizedContext();
+
+ // store the new LdapConnectionHandler in the PolicySource
+ mPolicySource.setConnectionHandler(mURL, mConnection);
+ }
+ mDataStore = mConnection.getDataStore();
+ }
+
+ /**ClosesOpens the connection to the datasource
+ *
+ * @throws <code>SPIException</code> if error occurs
+ * @throws CloseConnectionException if connection error occurs
+ */
+ public void close() throws SPIException {
+ if (mPolicySource.getConnectionHandler(mURL) != null) {
+ mPolicySource.setConnectionHandler(mURL, null);
+ }
+ mConnection.disconnect();
+ }
+
+ protected boolean isGSSAPIAuthentication() {
+ return mEnvironmentMgr.getProfileAuthType()
+ .equals(EnvironmentConstants.LDAP_AUTH_TYPE_GSSAPI);
+ }
+
+ /**
+ * Returns the default <code>ProfileRepository</code>
+ *
+ * @return the default <code>ProfileRepository</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ProfileRepository getDefaultProfileRepository()
+ throws SPIException {
+ Entity entity = mPolicySource.getRoot();
+ if (entity != null) {
+ return getProfileRepository(entity.getId());
+ }
+ return null;
+ }
+
+ /**
+ * Returns the requested <code>ProfileRepository</code>
+ *
+ * @param id the id for the required <code>ProfileRepository</code>
+ * @return the <code>ProfileRepository</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ProfileRepository getProfileRepository(String id)
+ throws SPIException {
+ return (ProfileRepository)new LdapProfileRepository(
+ id, mPolicySource);
+ }
+
+ /**
+ * Returns the requested <code>Profile</code>.
+ *
+ * @param id the id for the required <code>Profile</code>
+ * @return the <code>Profile</code> object
+ * or null if does not exist
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getProfile(String id) throws SPIException {
+ return mDataStore.getProfile(id);
+ }
+
+ /**
+ * Returns all the Profiles.
+ *
+ * @return an Iterator over all the Profile objects
+ * @throws SPIException if error occurs
+ */
+ public Iterator getAllProfiles() throws SPIException {
+ return mDataStore.getAllProfiles(
+ mPolicySource, (LdapEntity)mPolicySource.getRoot(), Applicability.getApplicability(mPolicySource.getName()));
+ }
+
+ /**
+ * Returns all the Profiles stored in the startingEntity
+ * and all of its sub-entities.
+ *
+ * @return an Iterator over all the Profile objects
+ * @throws SPIException if error occurs
+ */
+ public Iterator getAllProfiles(Entity startingEntity) throws SPIException {
+ return mDataStore.getAllProfiles(
+ mPolicySource, (LdapEntity)startingEntity, Applicability.getApplicability(mPolicySource.getName()));
+ }
+
+ public LdapDataStore getDataStore() {
+ return mDataStore;
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/profiles/LdapProfileRepository.java b/src/com/sun/apoc/spi/ldap/profiles/LdapProfileRepository.java
new file mode 100644
index 0000000..a6407f4
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/profiles/LdapProfileRepository.java
@@ -0,0 +1,305 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.ldap.profiles;
+
+import java.util.Iterator;
+import java.util.TreeSet;
+
+import com.sun.apoc.spi.AssignmentProvider;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Host;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore;
+import com.sun.apoc.spi.ldap.entities.LdapEntity;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileImpl;
+import com.sun.apoc.spi.profiles.ProfileRepositoryImpl;
+
+/**
+ * Class for an LDAP profile repository.
+ *
+ */
+public class LdapProfileRepository extends ProfileRepositoryImpl
+{
+ /** name for global profile container */
+ public static final String GLOBAL_PROFILE_CONTAINER =
+ "_GlobalPolicyGroups_";
+ /** Default name for entity (local) profile with user applicability */
+ public static final String DEFAULT_USER_PROFILE_NAME =
+ "_DefaultUserPolicyGroup_";
+ /** Default dn entry for local profile with user applicability */
+ public static final String DEFAULT_USER_PROFILE_DN =
+ "_defaultuserpolicygroup_";
+ /** Default name for entity (local) profile with host applicability */
+ public static final String DEFAULT_HOST_PROFILE_NAME =
+ "_DefaultHostPolicyGroup_";
+ /** Default dn entry for local profile with host applicability */
+ public static final String DEFAULT_HOST_PROFILE_DN =
+ "_defaulthostpolicygroup_";
+
+ protected Entity mRepositoryEntity;
+ private String mLocation;
+
+ /**
+ * Constructor.
+ *
+ * @param id entity id of this repository
+ * @param PolicyManager
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public LdapProfileRepository(String id, PolicySource aPolicySource)
+ throws SPIException {
+ mPolicySource = aPolicySource;
+ mEntityId = id;
+ setId();
+ mLocation = mId;
+ }
+
+ /**
+ * Finds a profile object given its displayname
+ *
+ * @param aDisplayName display name for profile
+ * @return object representing the profile
+ * or null if not found
+ * @throws <code>SPIException/code> if error
+ * occurs
+ */
+ public Profile findProfile(String aDisplayName)
+ throws SPIException {
+ return getDataStore().findProfile(this,aDisplayName);
+ }
+
+ /**
+ * Returns the location of the repository.
+ *
+ * @return the location
+ */
+ public String getLocation() {
+ return mLocation;
+ }
+
+ /**
+ * Sets the id to
+ * ou=_GlobalPolicyGroups_,ou=ApocRegistry,ou=default,
+ * ou=OrganizationConfig,ou=1.0,ou=ApocService,ou=services,<EntityId>
+ *
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setId() throws SPIException {
+ StringBuffer buf = new StringBuffer(LdapDataStore.BUFFER_LENGTH);
+ buf.append(LdapDataStore.CONFIG_NAMING_ATTR);
+ buf.append(LdapProfileRepository.GLOBAL_PROFILE_CONTAINER);
+ buf.append(LdapEntity.LDAP_SEPARATOR) ;
+ for (int i = 0 ;
+ i < LdapDataStore.NUMBER_OF_SERVICE_MAPPING_ELEMENTS ; ++ i) {
+ buf.append(LdapDataStore.SERVICE_MAPPING_ELEMENTS [i].getRDN()) ;
+ buf.append(LdapEntity.LDAP_SEPARATOR) ;
+ }
+ buf.append(((LdapEntity)getEntity()).getLocation());
+ mId = buf.toString();
+ }
+
+ /**
+ * Creates and returns a <code>Profile</code> object.
+ *
+ * @param aDisplayName the display name for the profile
+ * @param aApplicability applicablity of profile
+ * @param aPriority priority of the profile
+ * @return <code>Profile</code> object
+ * @throws SPIException if error occurs
+ */
+ protected Profile createTheProfile(String aDisplayName,
+ Applicability aApplicability,
+ int aPriority)
+ throws SPIException {
+ return getDataStore().createProfile(this, aDisplayName,
+ aApplicability, aPriority);
+ }
+
+ /**
+ * Deletes the profile <code>aProfile</code> from the repository
+ *
+ * @param aProfile the <code>Profile</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void deleteProfile(Profile aProfile)
+ throws SPIException {
+ getDataStore().destroyProfile(this, (ProfileImpl)aProfile);
+ }
+
+ /**
+ * Returns the requested profile or null if it does
+ * not exist.
+ *
+ * @param aId id for the required profile
+ * @return object representing profile
+ * or null if does not exist
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getProfile(String aId)
+ throws SPIException {
+ return getDataStore().getProfile(this, aId);
+ }
+
+ /**
+ * Returns the profiles of the specified scope.
+ *
+ * @param aApplicability scope of profiles required
+ * @return TreeSet of profiles matching
+ * the filter
+ * @throws SPIException if error occurs
+ */
+ protected TreeSet getTheProfiles(Applicability aApplicability)
+ throws SPIException {
+ return getDataStore().getProfiles(this, aApplicability);
+ }
+
+ /**
+ * Returns a boolean indicating if the current user has read only
+ * access for this profile repository.
+ *
+ * @return <code>true</code> if the current user has
+ * read only access
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean isReadOnly() throws SPIException {
+ Entity repositoryEntity = this.getEntity();
+ return !getDataStore().hasWriteAccess(this, repositoryEntity);
+ }
+
+ /**
+ * Returns the container entity.
+ *
+ * @return the container entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity() throws SPIException {
+ if (mRepositoryEntity == null) {
+ try {
+ mRepositoryEntity = mPolicySource.getEntity(mEntityId);
+ } catch (SPIException spie) { }
+ }
+ return mRepositoryEntity;
+ }
+
+ /**
+ * Returns the datastore.
+ *
+ * @return the datastore
+ */
+ public LdapDataStore getDataStore() {
+ return ((LdapProfileProvider)mPolicySource.getProfileProvider())
+ .getDataStore();
+ }
+
+ /**
+ * calculates the id of the Local Profile that would
+ * be stored in this repository if there was any
+ * Does not provide any garantee that such a profile
+ * exists in the repository.
+ * A Local Profile is a notion specific to APOC 1,
+ * this method enters in the process of supporting
+ * APOC 1 LDAP repositories.
+ *
+ * @return id of the Local Profile
+ * @throws SPIException if error occurs
+ */
+ public String getLocalProfileId () throws SPIException {
+ StringBuffer location = new StringBuffer();
+ // globalId: ou=_GlobalPolicyGroups_,
+ StringBuffer globalId = new StringBuffer();
+ globalId.append(LdapDataStore.CONFIG_NAMING_ATTR);
+ globalId.append(LdapProfileRepository.GLOBAL_PROFILE_CONTAINER);
+ globalId.append(LdapEntity.LDAP_SEPARATOR);
+ StringBuffer localId = new StringBuffer();
+ Entity entity = getEntity();
+ if ((entity instanceof Domain) || (entity instanceof Host)) {
+ // localId: ou=_defaulthostpolicygroup_,
+ localId.append(LdapDataStore.CONFIG_NAMING_ATTR);
+ localId.append(LdapProfileRepository.DEFAULT_HOST_PROFILE_DN);
+ localId.append(LdapEntity.LDAP_SEPARATOR) ;
+ }
+ else {
+ // localId: ou=_defaultuserpolicygroup_,
+ localId.append(LdapDataStore.CONFIG_NAMING_ATTR);
+ localId.append(LdapProfileRepository.DEFAULT_USER_PROFILE_DN);
+ localId.append(LdapEntity.LDAP_SEPARATOR) ;
+ }
+ String sGlobalId = globalId.toString();
+ if (mLocation.startsWith(sGlobalId)) {
+ location.append(localId.toString());
+ location.append(mLocation.substring(sGlobalId.length()));
+ return location.toString();
+ }
+ return mLocation;
+ }
+
+ /**
+ * Migrate a Local Profile from APOC 1 to APOC 2 format
+ * ie. from _defaultxxxpolicygroup_ to _GlobalPolicyGroups_/profileId
+ * As the profile is a Local Profile from APOC 1, we can
+ * safely assume that there is no entity explicitly assigned to it.
+ *
+ * @param profile profile to migrate
+ *
+ */
+ public void migrateProfile(LdapProfile profile) throws SPIException {
+ // create new profile
+ LdapProfile newProfile = (LdapProfile)this.createProfile(
+ profile.getDisplayName(), profile.getApplicability());
+ // add the profile policies to new profile
+ Iterator policies = profile.getPolicies();
+ while(policies.hasNext()) {
+ Policy policy = (Policy)policies.next();
+ newProfile.storePolicy(policy);
+ }
+ // assign the containing entity to the profile
+ AssignmentProvider assignmentProvider =
+ mPolicySource.getAssignmentProvider();
+ assignmentProvider.assignProfile(getEntity(), newProfile);
+ // low-level destruction so that we don't check
+ // if Entities are assigned which would return true all the time
+ this.deleteProfile(profile);
+ // copy the attributes of new profile into profile
+ // to midify the object referenced by the argument profile
+ profile.copy(newProfile);
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/profiles/LdapUserProfile.java b/src/com/sun/apoc/spi/ldap/profiles/LdapUserProfile.java
new file mode 100644
index 0000000..6f35bc6
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/profiles/LdapUserProfile.java
@@ -0,0 +1,356 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.profiles;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.User;
+import com.sun.apoc.spi.ldap.datastore.LdapDataStore ;
+import com.sun.apoc.spi.ldap.entities.mapping.LdapEntityMapping;
+import com.sun.apoc.spi.ldap.util.Timestamp ;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+
+import netscape.ldap.util.LDIF ;
+
+/**
+ *
+ *
+ */
+public class LdapUserProfile implements Profile {
+
+ /** Constants to generate the Policy data */
+ private static final String COMPONENT_PKG= "com.sun.jds";
+ private static final String COMPONENT_NAME= "UserProfile";
+ private static final String NODE_NAME= "Data";
+
+ /** Constants to initialise the Policy */
+ private static final String ID = "ou=UserProfile,";
+ private static final String DISPLAY_NAME = " User Profile";
+ private static final String POLICY_ID = COMPONENT_PKG+"."+COMPONENT_NAME;
+
+ private String mId;
+ private String mDisplayName = "";
+ private Policy mPolicy = null;
+
+ public LdapUserProfile(User user, Hashtable ldapAttributes) {
+ mId = ID+user.getId();
+ String data = getPolicyData(ldapAttributes);
+ byte [] timestamp =
+ (byte []) ldapAttributes.get(LdapDataStore.MODIFY_TIMESTAMP_ATTR) ;
+
+ if (timestamp != null) {
+ long lastModification = Timestamp.getMillis(new String(timestamp)) ;
+
+ mPolicy = new Policy(POLICY_ID, mId, data, lastModification) ;
+ }
+ else {
+ mPolicy = new Policy(POLICY_ID, mId, data);
+ }
+ mDisplayName = user.getDisplayName(null)+DISPLAY_NAME;
+}
+
+ /**
+ * Returns the policy object corresponding to the user profile.
+ *
+ * @return the policy object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Policy getPolicy() throws SPIException {
+ return mPolicy;
+ }
+
+ /** Header and trailer of the XML blob corresponding to the user profile. */
+ private static final String XML_HEADER =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" +
+ "<oor:component-data " +
+ "xmlns:oor=\"http://openoffice.org/2001/registry\" " +
+ "xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" " +
+ "oor:package=\"" + COMPONENT_PKG + "\" oor:name=\"" + COMPONENT_NAME +
+ "\"><node oor:name=\"" + NODE_NAME + "\">" ;
+ private static final String XML_TRAILER = "</node></oor:component-data>" ;
+ /**
+ * Generate the Policy blob from the Ldap attributes of the User
+ * and the attributes mapping
+ *
+ * @param ldapAttributes Ldap attributes and their values
+ * @return the Policy blob
+ */
+ private static String getPolicyData(Hashtable ldapAttributes) {
+ StringBuffer data = new StringBuffer(XML_HEADER);
+ Enumeration attributes = ldapAttributes.keys() ;
+
+ while (attributes.hasMoreElements()) {
+ String attribute = (String) attributes.nextElement() ;
+
+ data.append(
+ getPropertyData(attribute,
+ (byte []) ldapAttributes.get(attribute))) ;
+ }
+ data.append(XML_TRAILER) ;
+ return data.toString() ;
+ }
+
+ /** XML Strings used to build the prop node for a user profile attribute. */
+ private static final String PROP_HEADER = "<prop oor:name=\"" ;
+ private static final String PROP_MIDDLE =
+ "\" oor:type=\"xs:string\"><value>" ;
+ private static final String PROP_TRAILER = "</value></prop>" ;
+ /**
+ * returns the property data generated for a couple (key, value)
+ *
+ * @param key key of the property
+ * @param value value of the property
+ * @return property data generated
+ */
+ private static StringBuffer getPropertyData(String key, byte [] value) {
+ StringBuffer data = new StringBuffer();
+
+ if (value != null && value.length > 0 && LDIF.isPrintable(value)) {
+ data.append(PROP_HEADER) ;
+ data.append(key).append(PROP_MIDDLE) ;
+ int lastValid = 0 ;
+
+ for (int i = 0 ; i < value.length ; ++ i) {
+ byte current = value [i] ;
+ boolean special = current == '&' ||
+ current == '<' || current == '>' ;
+
+ if (special) {
+ if (i != lastValid) {
+ data.append(new String(value, lastValid,
+ i - lastValid)) ;
+ }
+ if (current == '&') { data.append("&amp;") ; }
+ else if (current == '<') { data.append("&lt;") ; }
+ else if (current == '>') { data.append("&gt;") ; }
+ lastValid = i + 1 ;
+ }
+ }
+ if (lastValid != value.length) {
+ data.append(new String(value, lastValid,
+ value.length - lastValid)) ;
+ }
+ data.append(PROP_TRAILER) ;
+ }
+ return data;
+ }
+
+ /**
+ * Returns the id for this profile.
+ *
+ * @return id for this profile
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the display name for this profile.
+ *
+ * @return display name for this profile
+ */
+ public String getDisplayName() {
+ return mDisplayName;
+ }
+
+ /**
+ * Returns the priority for this profile.
+ *
+ * @return 0
+ */
+ public int getPriority() {
+ return 0;
+ }
+
+ /**
+ * Returns the scope for this profile.
+ *
+ * @return Applicability.USER
+ */
+ public Applicability getApplicability() {
+ return Applicability.USER;
+ }
+
+ /**
+ * Returns the author for the last modification of this
+ * profile.
+ *
+ * @return empty String
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getAuthor() throws SPIException {
+ return new String("");
+ }
+ /**
+ * Returns the comment for this profile.
+ *
+ * @return empty String
+ * @throws SPIException if error occurs
+ */
+ public String getComment() throws SPIException{
+ return new String("");
+ }
+
+ /**
+ * Returns the time of the last modification of the profile.
+ *
+ * @return time of the creation of the Policy in milliseconds
+ * @throws SPIException if error occurs
+ */
+ public long getLastModified() throws SPIException {
+ return mPolicy.getLastModified();
+ }
+
+ /**
+ * Returns a boolean indicating whether or not this profile
+ * has policies.
+ *
+ * @return <code>true</code> if there are policies,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasPolicies() throws SPIException {
+ return (mPolicy != null);
+ }
+
+ /**
+ * Returns the policies for this profile.
+ *
+ * @return <code>Iterator</code> of all the policies
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicies() throws SPIException {
+ Vector policies = new Vector();
+ policies.add(mPolicy);
+ return policies.iterator();
+ }
+
+ /**
+ * Returns the policies for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the policies
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicies(Iterator aPolicyIdList)
+ throws SPIException {
+ Vector policies = new Vector();
+ String thePolicyId = mPolicy.getId();
+ while (aPolicyIdList.hasNext()) {
+ String policyId = (String)aPolicyIdList.next();
+ if (policyId.equals(thePolicyId)) {
+ policies.add(mPolicy);
+ break;
+ }
+ }
+ return policies.iterator();
+ }
+
+ /**
+ * Returns the PolicyInfos for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the PolicyInfos
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicyInfos(Iterator aPolicyIdList)
+ throws SPIException {
+ return getPolicies(aPolicyIdList);
+ }
+
+ /**
+ * Returns the requested policy object.
+ *
+ * @param aId the id for the required policy
+ * @return the policy object or null if no policy
+ * with aId exists
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Policy getPolicy(String aId) throws SPIException {
+ if (aId.equals(mPolicy.getId())) {
+ return mPolicy;
+ }
+ return null;
+ }
+
+ public ProfileRepository getProfileRepository() {
+ return null;
+ }
+
+ public void storePolicy(Policy aPolicy) throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void destroyPolicy(Policy aPolicy) throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasAssignedEntities() throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Iterator getAssignedEntities() throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setApplicability(Applicability aApplicability)
+ throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setComment(String aComment) throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setPriority(int aPriority) throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setDisplayName(String aDisplayName) throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/com/sun/apoc/spi/ldap/util/Timestamp.java b/src/com/sun/apoc/spi/ldap/util/Timestamp.java
new file mode 100644
index 0000000..eaf2f0b
--- /dev/null
+++ b/src/com/sun/apoc/spi/ldap/util/Timestamp.java
@@ -0,0 +1,96 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.ldap.util;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+public class Timestamp
+{
+ private static final TimeZone sUTC = TimeZone.getTimeZone( "UTC" );
+
+ public static final String sEpoch = "19700101000000Z";
+ public static final long sEpochMillis = getMillis( sEpoch );
+
+ public static String getTimestamp()
+ {
+ StringBuffer theBuffer = new StringBuffer( 15 );
+ Calendar theCalendar = Calendar.getInstance( sUTC );
+ theBuffer.append( theCalendar.get( Calendar.YEAR ) );
+ padAppend( theBuffer, theCalendar.get( Calendar.MONTH ) + 1 );
+ padAppend( theBuffer, theCalendar.get( Calendar.DAY_OF_MONTH ) );
+ padAppend( theBuffer, theCalendar.get( Calendar.HOUR_OF_DAY ) );
+ padAppend( theBuffer, theCalendar.get( Calendar.MINUTE ) );
+ padAppend( theBuffer, theCalendar.get( Calendar.SECOND ) );
+ theBuffer.append( "Z" );
+ return theBuffer.toString();
+ }
+
+ public static long getMillis( String inTimestamp )
+ {
+ if ( inTimestamp == null )
+ {
+ return sEpochMillis;
+ }
+ Calendar theCalendar = Calendar.getInstance( sUTC );
+ theCalendar.clear();
+ theCalendar.set(
+ Integer.parseInt( inTimestamp.substring( 0, 4 ) ),
+ Integer.parseInt( inTimestamp.substring( 4, 6 ) ) - 1,
+ Integer.parseInt( inTimestamp.substring( 6, 8 ) ),
+ Integer.parseInt( inTimestamp.substring( 8, 10 ) ),
+ Integer.parseInt( inTimestamp.substring( 10, 12 ) ),
+ Integer.parseInt( inTimestamp.substring( 12, 14 ) ) );
+ return theCalendar.getTimeInMillis();
+ }
+
+ public static boolean isNewer( String inTimestamp1, String inTimestamp2 )
+ {
+ String theTimestamp1 = inTimestamp1.substring( 0, 13 );
+ String theTimestamp2 = inTimestamp2.substring( 0, 13 );
+ return Long.parseLong( theTimestamp1 ) >
+ Long.parseLong( theTimestamp2 );
+ }
+
+
+ private static void padAppend( StringBuffer inBuffer, int inValue )
+ {
+ if ( inValue < 10 )
+ {
+ inBuffer.append( 0 );
+ }
+ inBuffer.append( inValue );
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/AssignmentProviderImpl.java b/src/com/sun/apoc/spi/memory/AssignmentProviderImpl.java
new file mode 100644
index 0000000..a69a7fa
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/AssignmentProviderImpl.java
@@ -0,0 +1,107 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only (\"GPL\") or
+ * the Common Development and Distribution License(\"CDDL\")
+ * (collectively, the \"License\"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * \"Portions Copyrighted [year] [name of copyright owner]\"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding \"[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license.\" If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.sun.apoc.spi.AssignmentProvider;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.profiles.Profile;
+
+public class AssignmentProviderImpl implements AssignmentProvider {
+
+ private Hashtable m_assignments = null;
+ private PolicySource m_mgr = null;
+
+ public AssignmentProviderImpl(PolicySource mgr) {
+ m_assignments = new Hashtable();
+ m_mgr = mgr;
+ }
+
+ public void open() {
+
+ }
+
+ public void close() {
+ m_mgr = null;
+ m_assignments.clear();
+ }
+
+ public void assignProfile(Entity entity, Profile profile) {
+ HashSet assignedProfiles = (HashSet) m_assignments.get(entity);
+ if (assignedProfiles == null) {
+ assignedProfiles = new HashSet();
+ m_assignments.put(entity, assignedProfiles);
+ }
+ assignedProfiles.add(profile);
+ }
+
+ public void unassignProfile(Entity entity, Profile profile) {
+ HashSet assignedProfiles = (HashSet) m_assignments.get(entity);
+ if (assignedProfiles != null) {
+ assignedProfiles.remove(profile);
+ }
+ }
+
+ public Iterator getAssignedProfiles(Entity entity) {
+ HashSet assignedProfiles = (HashSet) m_assignments.get(entity);
+ if (assignedProfiles != null) {
+ return assignedProfiles.iterator();
+ }
+ else {
+ return Collections.EMPTY_SET.iterator();
+ }
+ }
+
+ public Iterator getAssignedEntities(Profile profile) {
+ HashSet assignedEntities = new HashSet();
+ Iterator it = m_assignments.entrySet().iterator();
+ while(it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ Entity entity = (Entity) entry.getKey();
+ HashSet profiles = (HashSet) entry.getValue();
+ if (profiles.contains(profile)) {
+ assignedEntities.add(entity);
+ }
+ }
+ return assignedEntities.iterator();
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/entities/DomainImpl.java b/src/com/sun/apoc/spi/memory/entities/DomainImpl.java
new file mode 100644
index 0000000..df1e1ec
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/entities/DomainImpl.java
@@ -0,0 +1,64 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.entities;
+
+import java.util.Iterator;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Domain;
+
+public class DomainImpl extends EntityNodeImpl implements Domain {
+
+ public DomainImpl(PolicySource mgr, Entity parent, String id, String displayName) {
+ super(mgr, parent, id, displayName);
+ }
+
+ public Iterator findSubDomains(String filter, boolean recursive) {
+ return findEntities(filter, recursive);
+ }
+
+ public Iterator findHosts(String filter, boolean recursive) {
+ return findEntities(filter, recursive);
+ }
+
+ public Iterator getSubDomains() {
+ return getNodes();
+ }
+
+ public Iterator getHosts() {
+ return getLeaves();
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/entities/EntityImpl.java b/src/com/sun/apoc/spi/memory/entities/EntityImpl.java
new file mode 100644
index 0000000..666c149
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/entities/EntityImpl.java
@@ -0,0 +1,113 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.entities;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale ;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+
+
+public class EntityImpl implements Entity {
+
+ private String m_displayName = "";
+ private String m_id = "";
+ private Entity m_parent = null;
+ private PolicySource m_mgr = null;
+
+ public EntityImpl(PolicySource mgr, Entity parent, String id, String displayName) {
+ m_mgr = mgr;
+ m_parent = parent;
+ m_displayName = displayName;
+ m_id = id;
+ }
+
+ public String getDisplayName(Locale aLocale) {
+ return m_displayName;
+ }
+
+ public Iterator getAncestorNames(Locale aLocale) {
+ LinkedList ancestorNames = new LinkedList();
+ Entity parent = this.getParent();
+ while (parent != null) {
+ ancestorNames.add(0, parent.getDisplayName(aLocale));
+ parent = parent.getParent();
+ }
+ return ancestorNames.iterator();
+ }
+
+ public String getId() {
+ return m_id;
+ }
+
+ public Entity getParent() {
+ return m_parent;
+ }
+
+ public Iterator getAssignedProfiles() throws SPIException {
+ return m_mgr.getAssignmentProvider().getAssignedProfiles(this);
+ }
+
+ public void assignProfile(Profile profile) throws SPIException {
+ m_mgr.getAssignmentProvider().assignProfile(this, profile);
+ }
+
+ public void unassignProfile(Profile profile) throws SPIException {
+ m_mgr.getAssignmentProvider().unassignProfile(this, profile);
+ }
+
+ public Iterator getLayeredProfiles() throws SPIException {
+ // not implemented yet
+ return null;
+ }
+
+ public ProfileRepository getProfileRepository() throws SPIException {
+ if (getParent() != null) {
+ return m_mgr.getProfileProvider().getProfileRepository(getId());
+ } else {
+ return m_mgr.getProfileProvider().getDefaultProfileRepository();
+ }
+ }
+
+ public String getPolicySourceName() {
+ return m_mgr.getName();
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/entities/EntityNodeImpl.java b/src/com/sun/apoc/spi/memory/entities/EntityNodeImpl.java
new file mode 100644
index 0000000..5da932b
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/entities/EntityNodeImpl.java
@@ -0,0 +1,108 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.entities;
+
+import java.util.Iterator;
+import java.util.Hashtable;
+import java.util.HashSet;
+import java.util.Collections;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Node;
+import com.sun.apoc.spi.entities.Leaf;
+
+public class EntityNodeImpl extends EntityImpl implements Node {
+
+ private Hashtable m_children = null;
+ private HashSet m_nodes = null;
+ private HashSet m_leaves = null;
+
+ public EntityNodeImpl(PolicySource mgr, Entity parent, String id, String displayName) {
+ super(mgr, parent, id, displayName);
+ m_children = new Hashtable();
+ m_nodes = new HashSet();
+ m_leaves = new HashSet();
+ }
+
+ public Iterator findEntities(String aFilter, boolean aIsRecursive) {
+ return null; // not implemented yet
+ }
+
+ public Iterator getChildren() {
+ return m_children.values().iterator();
+ }
+
+ public boolean hasChildren() {
+ return !m_children.isEmpty();
+ }
+
+ public Iterator getNodes() {
+ return m_nodes.iterator();
+ }
+
+ public boolean hasNodes() {
+ return !m_nodes.isEmpty();
+ }
+
+ public Iterator getLeaves() {
+ return m_leaves.iterator();
+ }
+
+ public boolean hasLeaves() {
+ return !m_leaves.isEmpty();
+ }
+
+ public Iterator getRoles() {
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ public boolean hasRoles() {
+ return false;
+ }
+
+ public Entity getEntity(String id) {
+ return (Entity) m_children.get(id);
+ }
+
+ public void addChild(Entity entity) {
+ m_children.put(entity.getId(), entity);
+ if (entity instanceof Leaf) {
+ m_leaves.add(entity);
+ } else {
+ m_nodes.add(entity);
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/entities/EntityProviderImpl.java b/src/com/sun/apoc/spi/memory/entities/EntityProviderImpl.java
new file mode 100644
index 0000000..ded57cd
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/entities/EntityProviderImpl.java
@@ -0,0 +1,144 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.entities;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.entities.EntityTreeProvider;
+import com.sun.apoc.spi.entities.OrganizationTreeProvider;
+import com.sun.apoc.spi.entities.DomainTreeProvider;
+import com.sun.apoc.spi.entities.Organization;
+import com.sun.apoc.spi.entities.Domain;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Node;
+import com.sun.apoc.spi.SPIException;
+
+
+public class EntityProviderImpl implements EntityTreeProvider,
+ OrganizationTreeProvider, DomainTreeProvider
+{
+ protected OrganizationImpl m_orgRootEntity = null;
+ protected DomainImpl m_domainRootEntity = null;
+ protected PolicySource m_mgr = null;
+
+ public EntityProviderImpl(PolicySource mgr) {
+ m_mgr = mgr;
+ }
+
+ public Node getRootEntity() throws SPIException {
+ return m_orgRootEntity;
+ }
+
+ public Organization getRootOrganization() {
+ return m_orgRootEntity;
+ }
+
+ public Domain getRootDomain() {
+ return m_domainRootEntity;
+ }
+
+ public Entity getEntity(String id) throws SPIException {
+ Entity entity = m_orgRootEntity.getEntity(id);
+ if (entity == null) {
+ m_domainRootEntity.getEntity(id);
+ }
+ return entity;
+ }
+
+
+ public void open() {
+ initializeSampleData();
+ }
+
+
+ public void close() {
+ m_mgr = null;
+ m_orgRootEntity = null;
+ }
+
+ protected void initializeSampleData() {
+ m_orgRootEntity = new OrganizationImpl(m_mgr, null, "o=ITCompany", "Organization Tree Root");
+ EntityNodeImpl subOrg1 = new OrganizationImpl(m_mgr, m_orgRootEntity, "o=subOrg1, o=ITCompany", "Customer Care");
+ EntityNodeImpl subOrg2 = new OrganizationImpl(m_mgr, m_orgRootEntity, "o=subOrg2, o=ITCompany", "Development");
+ EntityNodeImpl subOrg3 = new OrganizationImpl(m_mgr, m_orgRootEntity, "o=subOrg3, o=ITCompany", "Sales");
+ EntityNodeImpl subOrg4 = new OrganizationImpl(m_mgr, m_orgRootEntity, "o=subOrg4, o=ITCompany", "Security");
+ m_orgRootEntity.addChild(subOrg1);
+ m_orgRootEntity.addChild(subOrg2);
+ m_orgRootEntity.addChild(subOrg3);
+ m_orgRootEntity.addChild(subOrg4);
+
+ EntityNodeImpl subOrg11 = new OrganizationImpl(m_mgr, subOrg1, "o=suborgA, o=subOrg1, o=ITCompany", "Call Center");
+ EntityNodeImpl subOrg12 = new OrganizationImpl(m_mgr, subOrg1, "o=suborgB, o=subOrg1, o=ITCompany", "Representatives");
+ subOrg1.addChild(subOrg11);
+ subOrg1.addChild(subOrg12);
+
+ EntityNodeImpl subOrg21 = new OrganizationImpl(m_mgr, subOrg2, "o=suborgA, o=subOrg2, o=ITCompany", "Hardware");
+ EntityNodeImpl subOrg22 = new OrganizationImpl(m_mgr, subOrg2, "o=suborgB, o=subOrg2, o=ITCompany", "Software");
+ subOrg2.addChild(subOrg21);
+ subOrg2.addChild(subOrg22);
+
+ EntityNodeImpl subOrg31 = new OrganizationImpl(m_mgr, subOrg3, "o=suborgA, o=subOrg3, o=ITCompany", "Call Center");
+ EntityNodeImpl subOrg32 = new OrganizationImpl(m_mgr, subOrg3, "o=suborgB, o=subOrg3, o=ITCompany", "Representatives");
+ subOrg3.addChild(subOrg31);
+ subOrg3.addChild(subOrg32);
+
+ Entity sample_user = new UserImpl(m_mgr, subOrg4, "uid=jclarke, o=subOrg4, o=ITCompany", "jmonroe");
+ subOrg4.addChild(sample_user);
+
+ for(int i=0; i < 10; i++) {
+ StringBuffer id = new StringBuffer("uid=user");
+ id.append(i);
+ id.append(", o=subOrg1, o=ITCompany");
+ StringBuffer name = new StringBuffer("user");
+ name.append(i);
+ Entity sample_user2 = new UserImpl(m_mgr, subOrg1, id.toString(), name.toString());
+ subOrg1.addChild(sample_user2);
+ }
+
+ m_domainRootEntity = new DomainImpl(m_mgr, null, "dc=Sun", "Domain Tree Root");
+ EntityNodeImpl subDomain = new DomainImpl(m_mgr, m_domainRootEntity, "dc=destiny, dc=Sun", "Destiny");
+ m_domainRootEntity.addChild(subDomain);
+
+ for(int i=0; i < 10; i++) {
+ StringBuffer id = new StringBuffer("ou=host");
+ id.append(i);
+ id.append(", dc=Sun, dc=destiny");
+ StringBuffer name = new StringBuffer("host");
+ name.append(i);
+ Entity host = new HostImpl(m_mgr, subDomain, id.toString(), name.toString());
+ subDomain.addChild(host);
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/entities/HostImpl.java b/src/com/sun/apoc/spi/memory/entities/HostImpl.java
new file mode 100644
index 0000000..20ef6ed
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/entities/HostImpl.java
@@ -0,0 +1,55 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.entities;
+
+import java.util.Iterator;
+import java.util.Collections;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.entities.Host;
+import com.sun.apoc.spi.entities.Entity;
+
+
+public class HostImpl extends EntityImpl implements Host {
+
+ public HostImpl(PolicySource mgr, Entity parent, String id, String displayName) {
+ super(mgr, parent, id, displayName);
+ }
+
+ public Iterator getMemberships() {
+ return Collections.EMPTY_LIST.iterator();
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/entities/OrganizationImpl.java b/src/com/sun/apoc/spi/memory/entities/OrganizationImpl.java
new file mode 100644
index 0000000..6d533ae
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/entities/OrganizationImpl.java
@@ -0,0 +1,64 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.entities;
+
+import java.util.Iterator;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.Organization;
+
+public class OrganizationImpl extends EntityNodeImpl implements Organization {
+
+ public OrganizationImpl(PolicySource mgr, Entity parent, String id, String displayName) {
+ super(mgr, parent, id, displayName);
+ }
+
+ public Iterator findSubOrganizations(String filter, boolean recursive) {
+ return findEntities(filter, recursive);
+ }
+
+ public Iterator findUsers(String filter, boolean recursive) {
+ return findEntities(filter, recursive);
+ }
+
+ public Iterator getSubOrganizations() {
+ return getNodes();
+ }
+
+ public Iterator getUsers() {
+ return getLeaves();
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/entities/UserImpl.java b/src/com/sun/apoc/spi/memory/entities/UserImpl.java
new file mode 100644
index 0000000..e3e4f4b
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/entities/UserImpl.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.entities;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.entities.User;
+import com.sun.apoc.spi.profiles.Profile;
+
+
+public class UserImpl extends EntityImpl implements User {
+
+ public UserImpl(PolicySource mgr, Entity parent, String id, String displayName) {
+ super(mgr, parent, id, displayName);
+ }
+
+ public String getUserId()
+ {
+ return getDisplayName(null);
+ }
+
+ public Iterator getMemberships() {
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ public Profile getUserProfile() throws SPIException {
+ return null;
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/profiles/ProfileImpl.java b/src/com/sun/apoc/spi/memory/profiles/ProfileImpl.java
new file mode 100644
index 0000000..007afd8
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/profiles/ProfileImpl.java
@@ -0,0 +1,182 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only (\"GPL\") or
+ * the Common Development and Distribution License(\"CDDL\")
+ * (collectively, the \"License\"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * \"Portions Copyrighted [year] [name of copyright owner]\"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding \"[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license.\" If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.profiles;
+
+import java.util.Iterator;
+import java.util.Hashtable;
+import java.util.ArrayList;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+import com.sun.apoc.spi.profiles.Applicability;
+
+
+public class ProfileImpl implements Profile {
+
+ public static final String ID_SEPARATOR = "/";
+
+ public static int m_idCounter = 0;
+
+ private int m_priority = 0;
+ private String m_id = "";
+ private String m_displayName = "";
+ private Applicability m_applicability = null;
+ private String m_comment = "";
+ private String m_author = "";
+ private Hashtable m_policies = null;
+ private Hashtable m_assignedEntities = null;
+
+ private ProfileRepositoryImpl m_parentRepository = null;
+
+ public ProfileImpl(ProfileRepositoryImpl parent, String displayName) {
+ m_parentRepository = parent;
+ m_policies = new Hashtable();
+ m_assignedEntities = new Hashtable();
+ setDisplayName(displayName);
+ m_id = parent.getId() + ID_SEPARATOR + m_idCounter;
+ m_idCounter++;
+ m_author = "test";
+ }
+
+ public String getId() {
+ return m_id;
+ }
+
+ public String getDisplayName() {
+ return m_displayName;
+ }
+
+ public int getPriority() {
+ return m_priority;
+ }
+
+ public long lastModified() {
+ return 0;
+ }
+
+ public void setPriority(int newPriority) {
+ m_priority = newPriority;
+ }
+
+ public void setDisplayName(String displayName) {
+ m_displayName = displayName;
+ }
+
+ public Policy createPolicy(String id, String data) {
+ Policy policy = new Policy(id, this.getId(), data);
+ m_policies.put(id, policy);
+ return policy;
+ }
+
+ public void storePolicy(Policy aPolicy) {
+ m_policies.put(aPolicy.getId(), aPolicy);
+ }
+
+ public void destroyPolicy(Policy policy) {
+ m_policies.remove(policy.getId());
+ }
+
+ public Iterator getPolicies() {
+ return m_policies.values().iterator();
+ }
+
+ public Iterator getPolicies(ArrayList list) {
+ return m_policies.values().iterator();
+ }
+
+ public Iterator getPolicies(Iterator policyIds) throws SPIException {
+ ArrayList policyList = new ArrayList();
+ while(policyIds.hasNext()) {
+ Policy policy = getPolicy((String) policyIds.next());
+ policyList.add(policy);
+ }
+ return policyList.iterator();
+ }
+
+ public Iterator getPolicyInfos(Iterator policyIds) throws SPIException {
+ // this shortcut is only allowed in the memory-based implementation!
+ return getPolicies(policyIds);
+ }
+
+ public boolean hasPolicies() {
+ return !m_policies.isEmpty();
+ }
+
+ public Policy getPolicy(String id) {
+ return (Policy) m_policies.get(id);
+ }
+
+ public Iterator getAssignedEntities() throws SPIException {
+ return m_parentRepository.getPolicySource().getAssignmentProvider().getAssignedEntities(this);
+ }
+
+ public boolean hasAssignedEntities() {
+ return false;
+ }
+
+ public Applicability getApplicability() {
+ return m_applicability;
+ }
+
+ public void setApplicability(Applicability applicability) {
+ m_applicability = applicability;
+ }
+
+ public String getComment() {
+ return m_comment;
+ }
+
+ public void setComment(String comment) {
+ m_comment = comment;
+ }
+
+ public String getAuthor() {
+ return m_author;
+ }
+
+ public ProfileRepositoryImpl getParentProfileRepository() {
+ return m_parentRepository;
+ }
+
+ public long getLastModified() {
+ return 0;
+ }
+
+ public ProfileRepository getProfileRepository() {
+ return m_parentRepository;
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/profiles/ProfileProviderImpl.java b/src/com/sun/apoc/spi/memory/profiles/ProfileProviderImpl.java
new file mode 100644
index 0000000..65ba7ae
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/profiles/ProfileProviderImpl.java
@@ -0,0 +1,153 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only (\"GPL\") or
+ * the Common Development and Distribution License(\"CDDL\")
+ * (collectively, the \"License\"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * \"Portions Copyrighted [year] [name of copyright owner]\"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding \"[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license.\" If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.profiles;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileProvider;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+
+
+public class ProfileProviderImpl implements ProfileProvider {
+
+ private static final String DEFAULT_REPOSITORY_ID = "default";
+
+ private static ProfileRepository m_defaultRepository = null;
+ private Hashtable m_repositories = null;
+ private PolicySource m_mgr = null;
+
+ public ProfileProviderImpl(PolicySource mgr) {
+ m_mgr = mgr;
+ }
+
+ public void open() {
+ m_defaultRepository = new ProfileRepositoryImpl(m_mgr, DEFAULT_REPOSITORY_ID);
+ m_repositories = new Hashtable();
+ m_repositories.put(DEFAULT_REPOSITORY_ID, m_defaultRepository);
+ initializeSampleData();
+ }
+
+ public void close() {
+ m_mgr = null;
+ m_repositories = null;
+ m_defaultRepository = null;
+ }
+
+ public ProfileRepository getDefaultProfileRepository() {
+ return m_defaultRepository;
+ }
+
+ public ProfileRepository getProfileRepository(String id) {
+ if (m_repositories.containsKey(id)) {
+ return (ProfileRepository) m_repositories.get(id);
+ } else {
+ ProfileRepository repository = new ProfileRepositoryImpl(m_mgr, id);
+ m_repositories.put(id, repository);
+ return repository;
+ }
+ }
+
+ public Iterator getProfileRepositories() {
+ return m_repositories.values().iterator();
+ }
+
+ public Profile getProfile(String id) throws SPIException {
+ int separatorPos = id.indexOf(ProfileImpl.ID_SEPARATOR);
+ if (separatorPos > 0) {
+ String repositoryId = id.substring(separatorPos);
+ ProfileRepository repository = getProfileRepository(repositoryId);
+ return repository.getProfile(id);
+ } else {
+ return null;
+ }
+ }
+
+ public Iterator getAllProfiles() throws SPIException {
+ ArrayList profileList = new ArrayList();
+
+ //first iterate over all repositories
+ Iterator it = getProfileRepositories();
+ while(it.hasNext()) {
+ ProfileRepository rep = (ProfileRepository) it.next();
+
+ // then iterate over all profiles stored in each repository
+ Iterator profileIt = rep.getProfiles(Applicability.ALL);
+ while(profileIt.hasNext()) {
+ Profile profile = (Profile) profileIt.next();
+ profileList.add(profile);
+ }
+ }
+ return profileList.iterator();
+ }
+
+ // not implemented
+ public Iterator getAllProfiles(Entity StartingEntity) throws SPIException {
+ throw new UnsupportedOperationException();
+ }
+
+ private void initializeSampleData() {
+ try {
+ Profile profile1 = m_defaultRepository.createProfile("StarOffice Novice", Applicability.ALL);
+ profile1.storePolicy(new Policy("com.sun.apoc.test", profile1.getId(), "Just some dummy data"));
+ profile1.storePolicy(new Policy("com.sun.apoc.test2", profile1.getId(), "and some more data"));
+
+ Profile profile2 = m_defaultRepository.createProfile("APOC Agent Settings", Applicability.ALL);
+ profile2.storePolicy(new Policy("com.sun.apoc.apocd", profile2.getId(), "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
+ + "<oor:component-data xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" oor:name=\"apocd\" oor:package=\"com.sun.apoc\">"
+ + "<prop oor:name=\"DaemonChangeDetectionInterval\" oor:finalized=\"true\" oor:type=\"xs:int\">"
+ + "<value>10</value></prop></oor:component-data>"));
+
+
+ Profile profile3 = m_defaultRepository.createProfile("Desktop Appearance", Applicability.ALL);
+ profile3.storePolicy(new Policy("org.gnome.desktop.gnome", profile2.getId(), "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
+ + "<oor:component-data xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" oor:name=\"gnome\" oor:package=\"org.gnome.desktop\">"
+ + "<node oor:name=\"background\">"
+ + "<prop oor:name=\"primary_color\" oor:type=\"xs:string\">"
+ + "<value>#c06600</value>"
+ + "</prop></node></oor:component-data>"));
+ } catch (SPIException ex) {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/com/sun/apoc/spi/memory/profiles/ProfileRepositoryImpl.java b/src/com/sun/apoc/spi/memory/profiles/ProfileRepositoryImpl.java
new file mode 100644
index 0000000..82c2d07
--- /dev/null
+++ b/src/com/sun/apoc/spi/memory/profiles/ProfileRepositoryImpl.java
@@ -0,0 +1,106 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only (\"GPL\") or
+ * the Common Development and Distribution License(\"CDDL\")
+ * (collectively, the \"License\"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * \"Portions Copyrighted [year] [name of copyright owner]\"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding \"[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license.\" If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.memory.profiles;
+
+import java.util.Iterator;
+import java.util.Hashtable;
+import java.io.OutputStream;
+import java.io.InputStream;
+import com.sun.apoc.spi.PolicySource;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+import com.sun.apoc.spi.entities.Entity;
+
+public class ProfileRepositoryImpl implements ProfileRepository {
+
+ private String m_id = "";
+ private Hashtable m_profiles = null;
+ private PolicySource m_mgr = null;
+
+ public ProfileRepositoryImpl(PolicySource mgr, String id) {
+ m_id = id;
+ m_mgr = mgr;
+ m_profiles = new Hashtable();
+ }
+
+ public Profile createProfile(String displayName, Applicability applicability)
+ throws SPIException {
+ Profile newProfile = new ProfileImpl(this, displayName);
+ newProfile.setApplicability(applicability);
+ m_profiles.put(newProfile.getId(), newProfile);
+ return newProfile;
+ }
+
+ public void destroyProfile(Profile profile) {
+ m_profiles.remove(profile.getId());
+ }
+
+ public Profile getProfile(String id) {
+ return (Profile) m_profiles.get(id);
+ }
+
+ public Profile findProfile(String aDisplayName) {
+ return null;
+ }
+
+ public Iterator getProfiles(Applicability applicability) {
+ return m_profiles.values().iterator();
+ }
+
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ public String getId() {
+ return m_id;
+ }
+
+ public PolicySource getPolicySource() {
+ return m_mgr;
+ }
+
+ public Entity getEntity() {
+ return null;
+ }
+
+ public void exportProfile(Profile profile, OutputStream out) {
+ }
+
+ public void importProfile(String name, Applicability app, InputStream out) {
+ }
+}
diff --git a/src/com/sun/apoc/spi/policies/InvalidPolicyException.java b/src/com/sun/apoc/spi/policies/InvalidPolicyException.java
new file mode 100644
index 0000000..ce7e20a
--- /dev/null
+++ b/src/com/sun/apoc/spi/policies/InvalidPolicyException.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.policies;
+
+public class InvalidPolicyException extends PolicyException {
+
+ private static final String NULL_POLICY_KEY =
+ "error.spi.policy.null";
+ public static final String NULL_POLICIES_KEY =
+ "error.spi.policies.null";
+
+ public InvalidPolicyException () {
+ super();
+ mMessageKey = NULL_POLICY_KEY;
+ }
+
+ public InvalidPolicyException (String messageKey) {
+ super();
+ mMessageKey = messageKey;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/policies/MismatchPolicyException.java b/src/com/sun/apoc/spi/policies/MismatchPolicyException.java
new file mode 100644
index 0000000..1e62d76
--- /dev/null
+++ b/src/com/sun/apoc/spi/policies/MismatchPolicyException.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.policies;
+
+
+public class MismatchPolicyException extends PolicyException {
+
+ private static final String MISMATCH_POLICYTREE_KEY =
+ "error.spi.policy.mismatch";
+
+ public MismatchPolicyException () {
+ super();
+ mMessageKey = MISMATCH_POLICYTREE_KEY;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/policies/NoSuchPolicyException.java b/src/com/sun/apoc/spi/policies/NoSuchPolicyException.java
new file mode 100644
index 0000000..b8f30a2
--- /dev/null
+++ b/src/com/sun/apoc/spi/policies/NoSuchPolicyException.java
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.policies;
+
+public class NoSuchPolicyException extends PolicyException {
+
+ private static final String NO_POLICY =
+ "error.spi.policy.noexist";
+
+ private String mPolicyId;
+
+ public NoSuchPolicyException () {
+ super();
+ }
+
+ public NoSuchPolicyException (String policyId) {
+ super();
+ mPolicyId = policyId;
+ mMessageKey = NO_POLICY;
+ mMessageParams = new Object[] {mPolicyId};
+ }
+
+ public String getPolicyId() { return mPolicyId; }
+}
diff --git a/src/com/sun/apoc/spi/policies/Policy.java b/src/com/sun/apoc/spi/policies/Policy.java
new file mode 100644
index 0000000..7a7919e
--- /dev/null
+++ b/src/com/sun/apoc/spi/policies/Policy.java
@@ -0,0 +1,110 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.policies;
+
+
+
+/**
+ * Object representing a Policy in memory
+ * (no interaction with the backend).
+ *
+ */
+public class Policy extends PolicyInfo {
+ protected String mData;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aProfileId identifier of the Profile containing
+ * this Policy
+ * @param aData data stored (XMLBlob)
+ * @param aLastModified time in milliseconds of the last modification
+ * of this Policy
+ */
+ public Policy(String aId, String aProfileId, String aData, long aLastModified) {
+ super(aId, aProfileId, aLastModified);
+ mData = aData;
+ }
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aProfileId identifier of the Profile containing
+ * this Policy
+ * @param aData data stored (XMLBlob)
+ */
+ public Policy(String aId, String aProfileId, String aData) {
+ super(aId, aProfileId);
+ mData = aData;
+ }
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aData data stored (XMLBlob)
+ */
+ public Policy(String aId, String aData) {
+ super(aId);
+ mData = aData;
+ }
+
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aData data stored (XMLBlob)
+ * @param aLastModified time in milliseconds of the last modification
+ * of this Policy
+ */
+ public Policy(String aId, String aData, long aLastModified) {
+ super(aId);
+ mData = aData;
+ mLastModified = aLastModified;
+ }
+
+ /**
+ * Returns the data XMLBlob for the policy.
+ *
+ * @return policy data
+ */
+ public String getData() {
+ return mData;
+ }
+}
diff --git a/src/com/sun/apoc/spi/policies/PolicyException.java b/src/com/sun/apoc/spi/policies/PolicyException.java
new file mode 100644
index 0000000..27e975a
--- /dev/null
+++ b/src/com/sun/apoc/spi/policies/PolicyException.java
@@ -0,0 +1,45 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.policies;
+
+import com.sun.apoc.spi.SPIException;
+
+public class PolicyException extends SPIException {
+
+ public PolicyException () {
+ super();
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/policies/PolicyInfo.java b/src/com/sun/apoc/spi/policies/PolicyInfo.java
new file mode 100644
index 0000000..f047930
--- /dev/null
+++ b/src/com/sun/apoc/spi/policies/PolicyInfo.java
@@ -0,0 +1,110 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.policies;
+
+/**
+ * Object representing some information about a Policy
+ * in memory (no interaction with the backend).
+ *
+ */
+public class PolicyInfo {
+ protected String mId;
+ protected long mLastModified=-1;
+ protected String mProfileId;
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aProfileId identifier of the Profile containing
+ * this Policy
+ * @param aLastModified time in milliseconds of the last modification
+ * of this Policy
+ */
+ public PolicyInfo(String aId, String aProfileId, long aLastModified) {
+ mId = aId;
+ mProfileId = aProfileId;
+ mLastModified = aLastModified;
+ }
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ * @param aProfileId identifier of the Profile containing
+ * this Policy
+ */
+ public PolicyInfo(String aId, String aProfileId) {
+ this(aId, aProfileId, System.currentTimeMillis());
+ }
+
+ /**
+ * Constructor for class.
+ *
+ * @param aId identifier
+ */
+ public PolicyInfo(String aId) {
+ mId = aId;
+ mLastModified = System.currentTimeMillis();
+ }
+
+ /**
+ * Returns the id for this policy.
+ *
+ * @return id for the policy
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the id of the profile containing this policy.
+ *
+ * @return profile id
+ */
+ public String getProfileId() {
+ return mProfileId;
+ }
+
+ /**
+ * Returns the time of the last modification of the policy.
+ *
+ * @return time of the last modification in milliseconds
+ * returns -1 if the time hasn't been initialized.
+ */
+ public long getLastModified() {
+ return mLastModified;
+ }
+}
diff --git a/src/com/sun/apoc/spi/profiles/Applicability.java b/src/com/sun/apoc/spi/profiles/Applicability.java
new file mode 100644
index 0000000..fc16ff3
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/Applicability.java
@@ -0,0 +1,129 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.profiles;
+
+import com.sun.apoc.spi.environment.EnvironmentConstants ;
+import com.sun.apoc.spi.util.StringRangeEnum;
+
+/**
+ * Handles the possible applications for a profile and
+ * their storage as integers.
+ *
+ */
+public class Applicability extends StringRangeEnum
+{
+ /** Symbolic string for unknown */
+ public static final String STR_UNKNOWN = "UNKNOWN";
+ /** Symbolic string for org use */
+ public static final String STR_USER = EnvironmentConstants.USER_SOURCE ;
+ /** Symbolic string for host use */
+ public static final String STR_HOST = EnvironmentConstants.HOST_SOURCE ;
+ /** Symbolic string for all use */
+ public static final String STR_ALL = "ALL";
+ /** Symbolic int value for unknown use */
+ private static final int INT_UNKNOWN = 0 ;
+ /** Symoblic int value for org use */
+ private static final int INT_USER = 1 ;
+ /** Symbolic int value for domain use */
+ private static final int INT_HOST = 2 ;
+ /** Symbolic int value for user and host use */
+ private static final int INT_ALL = 3 ;
+
+ public static final Applicability UNKNOWN =
+ new Applicability(INT_UNKNOWN) ;
+ public static final Applicability USER = new Applicability(INT_USER);
+ public static final Applicability HOST = new Applicability(INT_HOST);
+ public static final Applicability ALL = new Applicability(INT_ALL);
+
+ /**
+ * Array aligned on int values of possible types
+ * to provide a string equivalent.
+ */
+ private static final String enumStrings [] = {
+ STR_UNKNOWN,
+ STR_USER,
+ STR_HOST,
+ STR_ALL
+
+ } ;
+
+ private static final Applicability enums[] = {
+ UNKNOWN,
+ USER,
+ HOST,
+ ALL
+ };
+
+ private Applicability(int n) {
+ super(n);
+ }
+
+ protected String[] getEnumStrings() {
+ return enumStrings;
+ }
+
+ protected Applicability[] getEnums() {
+ return enums;
+ }
+
+ /**
+ * Factory method for Applicability instances where a
+ * string is the parameter.
+ *
+ * @param aString string name
+ * @return the corresponding <code>Applicability</code>
+ */
+ public static Applicability getApplicability(String aString) {
+ for (int i=0; i < enumStrings.length; i++) {
+ if (aString.equals(enumStrings[i])){
+ return enums[i];
+ }
+ }
+ return Applicability.UNKNOWN;
+ }
+
+ public boolean equals (Object aApplicability) {
+ if (aApplicability instanceof Applicability) {
+ int thisValue = this.getIntValue();
+ int appValue = ((Applicability)aApplicability).getIntValue();
+ return thisValue == appValue;
+ }
+ else if (aApplicability instanceof String) {
+ return aApplicability.equals(getStringValue()) ;
+ }
+ return false;
+ }
+}
diff --git a/src/com/sun/apoc/spi/profiles/InvalidDisplayNameException.java b/src/com/sun/apoc/spi/profiles/InvalidDisplayNameException.java
new file mode 100644
index 0000000..5fe8295
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/InvalidDisplayNameException.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+public class InvalidDisplayNameException extends ProfileException {
+
+ private static final String NULL_NAME_PROFILE_KEY =
+ "error.spi.profile.name.null";
+ private static final String INVALID_NAME_PROFILE_KEY =
+ "error.spi.profile.name.invalid";
+
+ protected String mDisplayName = null;
+
+ public InvalidDisplayNameException () {
+ super();
+ mMessageKey = NULL_NAME_PROFILE_KEY;
+ }
+
+ public InvalidDisplayNameException (String displayName) {
+ super();
+ mDisplayName = displayName;
+ mMessageKey = INVALID_NAME_PROFILE_KEY;
+ mMessageParams = new Object[]{mDisplayName};
+ }
+
+ public InvalidDisplayNameException (String messageKey, String displayName) {
+ super();
+ mDisplayName = displayName;
+ mMessageKey = messageKey;
+ mMessageParams = new Object[]{mDisplayName};
+ }
+
+ public String getDisplayName() {return mDisplayName;}
+}
diff --git a/src/com/sun/apoc/spi/profiles/InvalidPriorityException.java b/src/com/sun/apoc/spi/profiles/InvalidPriorityException.java
new file mode 100644
index 0000000..28609e4
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/InvalidPriorityException.java
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+public class InvalidPriorityException extends ProfileException {
+
+ public static final String USED_PRIORITY_KEY =
+ "error.spi.profile.priority.used";
+ public static final String INVALID_PRIORITY_KEY =
+ "error.spi.profile.priority.invalid";
+
+ protected int mPriority;
+
+ public InvalidPriorityException () {
+ super();
+ }
+
+ public InvalidPriorityException (String messageKey, int priority) {
+ super();
+ mPriority = priority;
+ mMessageKey = messageKey;
+ mMessageParams = new Object[]{new Integer(mPriority)};
+ }
+
+ public int getPriority() { return mPriority; }
+}
diff --git a/src/com/sun/apoc/spi/profiles/InvalidProfileException.java b/src/com/sun/apoc/spi/profiles/InvalidProfileException.java
new file mode 100644
index 0000000..fcd1c2e
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/InvalidProfileException.java
@@ -0,0 +1,72 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+public class InvalidProfileException extends ProfileException {
+
+ private static final String INVALID_PROFILE_KEY =
+ "error.spi.profile.invalid";
+ public static final String ASSIGNED_PROFILE_KEY =
+ "error.spi.profile.invalid.assigned";
+ public static final String EMPTY_PROFILE_KEY =
+ "error.spi.profile.invalid.empty";
+ public static final String NO_EXIST_PROFILE_KEY =
+ "error.spi.profile.invalid.noexist";
+ public static final String ID_PROFILE_KEY =
+ "error.spi.profile.invalid.id";
+
+ public InvalidProfileException () {
+ super();
+ mMessageKey = INVALID_PROFILE_KEY;
+ }
+
+ public InvalidProfileException (String key) {
+ super();
+ mMessageKey = key;
+ }
+
+ public InvalidProfileException (String key, String profileId) {
+ super();
+ mMessageKey = key;
+ mMessageParams = new Object[]{profileId};
+ }
+
+ public InvalidProfileException (String key, String profileId,
+ Throwable cause) {
+ super(cause);
+ mMessageKey = key;
+ mMessageParams = new Object[]{profileId};
+ }
+}
diff --git a/src/com/sun/apoc/spi/profiles/NullProfileException.java b/src/com/sun/apoc/spi/profiles/NullProfileException.java
new file mode 100644
index 0000000..aa0efef
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/NullProfileException.java
@@ -0,0 +1,46 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+public class NullProfileException extends ProfileException {
+ private static final String NULL_PROFILE_KEY =
+ "error.spi.profile.null";
+
+ public NullProfileException () {
+ super();
+ mMessageKey = NULL_PROFILE_KEY;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/profiles/Profile.java b/src/com/sun/apoc/spi/profiles/Profile.java
new file mode 100644
index 0000000..a16543c
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/Profile.java
@@ -0,0 +1,235 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.profiles;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.AssignmentProvider;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Interface for a profile.
+ *
+ */
+public interface Profile
+{
+ /**
+ * Returns the id for this profile.
+ *
+ * @return id for this profile
+ */
+ public String getId() ;
+
+ /**
+ * Returns the display name for this profile.
+ *
+ * @return display name for this profile
+ */
+ public String getDisplayName() ;
+
+ /**
+ * Returns the priority for this profile.
+ *
+ * @return priority for this profile
+ */
+ public int getPriority() ;
+
+ /**
+ * Returns the time of the last modification of the profile.
+ *
+ * @return time of the last modification in milliseconds
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public long getLastModified() throws SPIException;
+
+ /**
+ * Sets the priority for this profile.
+ *
+ * @param aPriority priority for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setPriority(int aPriority) throws SPIException;
+
+ /**
+ * Sets the display name for this profile.
+ *
+ * @param aDisplayName new display name for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setDisplayName(String aDisplayName)
+ throws SPIException;
+
+ /**
+ * Stores a <code>Policy</code>.
+ *
+ * @param aPolicy the policy to store
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void storePolicy(Policy aPolicy) throws SPIException;
+
+ /**
+ * Destroys a <code>Policy</code>.
+ *
+ * @param aPolicy the policy object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void destroyPolicy(Policy aPolicy) throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this profile
+ * has policies.
+ *
+ * @return <code>true</code> if there are policies,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasPolicies() throws SPIException;
+
+ /**
+ * Returns the policies for this profile.
+ *
+ * @return <code>Iterator</code> of all the policies
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicies() throws SPIException;
+
+ /**
+ * Returns the policies for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the policies
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicies(Iterator aPolicyIdList)
+ throws SPIException;
+
+ /**
+ * Returns the PolicyInfos for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the PolicyInfos
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getPolicyInfos(Iterator aPolicyIdList)
+ throws SPIException;
+
+ /**
+ * Returns the requested policy object.
+ *
+ * @param aId the id for the required policy
+ * @return the policy object or null if no policy
+ * with aId exists
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Policy getPolicy(String aId) throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this profile
+ * has been assigned to entities.
+ *
+ * @return <code>true</code> if there are entities,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean hasAssignedEntities() throws SPIException;
+
+ /**
+ * Returns the entities to which this profile has been assigned.
+ * Returns only the entities that have a type
+ * compatible with the profile Applicability.
+ *
+ * @return <code>Iterator</code> of entities
+ * @throws <code>SPIException</code> if error occurs
+ * @see AssignmentProvider#assignProfile(Entity, Profile)
+ */
+ public Iterator getAssignedEntities() throws SPIException;
+
+ /**
+ * Returns the scope for this profile.
+ *
+ * @return scope
+ */
+ public Applicability getApplicability() ;
+
+ /**
+ * Sets the scope for this profile.
+ *
+ * @param aApplicability scope
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setApplicability(Applicability aApplicability)
+ throws SPIException;
+
+ /**
+ * Returns the comment for this profile.
+ *
+ * @return comment
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getComment() throws SPIException;
+
+ /**
+ * Sets the comment for this profile. If the new
+ * comment is null then the existing comment is removed.
+ *
+ * @param aComment comment as a String
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setComment(String aComment) throws SPIException;
+
+ /**
+ * Returns the author for the last modification of this
+ * profile.
+ *
+ * @return name of the user that last modified this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public String getAuthor() throws SPIException;
+
+ /**
+ * Returns the <code>ProfileRepository</code> for this profile.
+ *
+ * @return <code>ProfileRepository</code>
+ */
+ public ProfileRepository getProfileRepository();
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileComparatorProvider.java b/src/com/sun/apoc/spi/profiles/ProfileComparatorProvider.java
new file mode 100644
index 0000000..4dbbb29
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileComparatorProvider.java
@@ -0,0 +1,50 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+import java.util.Comparator;
+
+/**
+ * provides access to a Comparator of Profiles
+ *
+ */
+public interface ProfileComparatorProvider {
+
+ /**
+ * Returns a Comparator object used to order the Profiles
+ * @return a comparator to order Profiles
+ */
+ public Comparator getProfileComparator();
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileException.java b/src/com/sun/apoc/spi/profiles/ProfileException.java
new file mode 100644
index 0000000..37c7dbe
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileException.java
@@ -0,0 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+import com.sun.apoc.spi.SPIException;
+
+public class ProfileException extends SPIException {
+
+ public ProfileException () {
+ super();
+ }
+ public ProfileException (Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileImpl.java b/src/com/sun/apoc/spi/profiles/ProfileImpl.java
new file mode 100644
index 0000000..f2262d3
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileImpl.java
@@ -0,0 +1,283 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.profiles;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.policies.Policy;
+
+/**
+ * Implementation for an LDAP profile.
+ *
+ */
+public abstract class ProfileImpl implements Profile
+{
+ /** undefined priority */
+ public static final int UNDEFINED_PRIORITY = 0 ;
+
+ protected String mId;
+ protected ProfileRepositoryImpl mRepository;
+ protected String mDisplayName;
+ protected Applicability mApplicability;
+ protected int mPriority;
+ protected Vector mPolicies;
+ protected String mComment;
+ protected boolean mNoCommentFound = false;
+ protected Entity mAuthor;
+
+ /**
+ * Constructor.
+ *
+ * @param aId id
+ * @param aRepository <code>ProfileRepository</code> object
+ * @param aDisplayName display name
+ * @param aApplicability scope for the profile
+ * @param aPriority priority
+ */
+ public ProfileImpl(String aId, ProfileRepositoryImpl aRepository,
+ String aDisplayName, Applicability aApplicability,
+ int aPriority) {
+ mId = aId;
+ mRepository = aRepository;
+ mDisplayName = aDisplayName;
+ mApplicability = aApplicability;
+ mPriority = aPriority;
+ }
+
+ /**
+ * Returns the id for this profile.
+ *
+ * @return id for this profile
+ */
+ public String getId() { return mId; }
+
+ /**
+ * Returns the <code>ProfileRepository</code> for this profile.
+ *
+ * @return <code>ProfileRepository</code>
+ */
+ public ProfileRepository getProfileRepository() { return mRepository; }
+
+ /**
+ * Returns the scope for this profile.
+ *
+ * @return scope for this profile
+ */
+ public Applicability getApplicability() { return mApplicability; }
+
+ /**
+ * Returns the priority for this profile.
+ *
+ * @return priority for this profile
+ */
+ public int getPriority() { return mPriority; }
+
+ /**
+ * Sets the priority for this profile.
+ *
+ * @param aPriority priority for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void setPriority(int aPriority)
+ throws SPIException;
+
+ /**
+ * Sets the display name for this profile.
+ *
+ * @param aDisplayName new display name for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void setDisplayName(String aDisplayName)
+ throws SPIException;
+
+ /**
+ * Stores a <code>Policy</code>.
+ *
+ * @param aPolicy the policy to store
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void storePolicy(Policy aPolicy)
+ throws SPIException;
+
+ /**
+ * Destroys a <code>Policy</code>.
+ *
+ * @param aPolicy the policy object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void destroyPolicy(Policy aPolicy)
+ throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this profile
+ * has policies.
+ *
+ * @return <code>true</code> if there are policies,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract boolean hasPolicies() throws SPIException;
+
+ /**
+ * Returns the policies for this profile.
+ *
+ * @return <code>Iterator</code> of all the policies for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Iterator getPolicies() throws SPIException;
+
+ /**
+ * Returns the policies for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the policies
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Iterator getPolicies(Iterator aPolicyIdList)
+ throws SPIException;
+
+ /**
+ * Returns the PolicyInfos for this profile that match the specified
+ * policy ids.
+ *
+ * @param aPolicyIdList list of policy ids
+ * @return <code>Iterator</code> of all the PolicyInfos
+ * for this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Iterator getPolicyInfos(Iterator aPolicyIdList)
+ throws SPIException;
+
+ /**
+ * Returns the requested policy object.
+ *
+ * @param aId the id for the required policy
+ * @return the policy object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Policy getPolicy(String aId) throws SPIException;
+
+ /**
+ * Returns a boolean indicating whether or not this profile
+ * has been assigned to entities.
+ *
+ * @return <code>true</code> if there are entities,
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract boolean hasAssignedEntities() throws SPIException;
+
+ /**
+ * Returns the entities to which this profile has been assigned.
+ *
+ * @return <code>Iterator</code> of entities
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Iterator getAssignedEntities()
+ throws SPIException;
+
+ /**
+ * Sets the scope for this profile.
+ *
+ * @param aApplicabiltiy scope
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void setApplicability(Applicability aApplicability)
+ throws SPIException;
+
+ /**
+ * Returns the time in milliseconds of the most
+ * recent modification of the profile entry and
+ * its policies.
+ *
+ * @return time of the last modification in milliseconds
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract long getLastModified() throws SPIException;
+
+ /**
+ * Returns the comment for this profile.
+ *
+ * @return comment
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract String getComment() throws SPIException;
+
+ /**
+ * Sets the comment for this profile object.
+ *
+ * @param aComment description
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void setExistingComment(String aComment) {
+ if (aComment == null) { mNoCommentFound = true; }
+ mComment = aComment;
+ }
+
+ /**
+ * Sets the comment for this profile. If the new
+ * comment is null then the existing comment is removed.
+ *
+ * @param aComment comment as a String
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract void setComment(String aComment)
+ throws SPIException;
+
+ /**
+ * Sets the author for the last modification of this
+ * profile entry.
+ *
+ * @param aAuthor entity that last modified this profile entry
+ */
+ public void setAuthor(Entity aAuthor) {
+ mAuthor = aAuthor;
+ }
+
+ /**
+ * Returns the author for the last modification of this
+ * profile.
+ *
+ * @return name of the user that last modified this profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract String getAuthor() throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileProvider.java b/src/com/sun/apoc/spi/profiles/ProfileProvider.java
new file mode 100644
index 0000000..1474242
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileProvider.java
@@ -0,0 +1,93 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+import java.util.Iterator;
+
+import com.sun.apoc.spi.Provider;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+
+/**
+ * Provides access to the Profiles
+ *
+ */
+public interface ProfileProvider extends Provider {
+
+ /**
+ * Returns the default <code>ProfileRepository</code>
+ *
+ * @return the default <code>ProfileRepository</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ProfileRepository getDefaultProfileRepository()
+ throws SPIException;
+
+ /**
+ * Returns the requested <code>ProfileRepository</code>
+ *
+ * @param id the id for the required <code>ProfileRepository</code>
+ * @return the <code>ProfileRepository</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public ProfileRepository getProfileRepository(String id)
+ throws SPIException;
+
+ /**
+ * Returns the requested <code>Profile</code>.
+ *
+ * @param id the id for the required <code>Profile</code>
+ * @return the <code>Profile</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getProfile(String id) throws SPIException;
+
+ /**
+ * Returns all the <code>Profile</code>s.
+ *
+ * @return an Iterator over all the <code>Profile</code> objects
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getAllProfiles() throws SPIException;
+
+ /**
+ * Returns all the Profiles stored in the startingEntity
+ * and all of its sub-entities.
+ *
+ * @return an Iterator over all the Profile objects
+ * @throws SPIException if error occurs
+ */
+ public Iterator getAllProfiles(Entity startingEntity) throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileRepository.java b/src/com/sun/apoc/spi/profiles/ProfileRepository.java
new file mode 100644
index 0000000..f3eb79a
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileRepository.java
@@ -0,0 +1,156 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.profiles;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+
+/**
+ * Interface for a profile repository.
+ *
+ */
+public interface ProfileRepository
+{
+ /** Possible formats for import/export. */
+ public static final int FORMAT_ZIP = 1 ;
+
+ /**
+ * Creates and returns a <code>Profile</code> object.
+ *
+ * @param aDisplayName the display name for the profile
+ * @param aApplicability applicablity of profile
+ * @return <code>Profile</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile createProfile(String aDisplayName,
+ Applicability aApplicability)
+ throws SPIException;
+
+ /**
+ * Deletes a <code>Profile</code> object.
+ *
+ * @param aProfile the <code>Profile</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void destroyProfile(Profile aProfile)
+ throws SPIException;
+
+ /**
+ * Exports a <code>Profile</code> object.
+ *
+ * @param aProfile the <code>Profile</code> object
+ * @param aOutput output stream
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public void exportProfile(Profile aProfile,
+ OutputStream aOutput)
+ throws SPIException;
+
+ /**
+ * Imports a profile from a stream in default format.
+ *
+ * @param aDisplayName display name for profile
+ * @param aApplicability scope
+ * @param aInput stream from which the profile will be imported
+ * @throws SPIException if an error occurs.
+ */
+ public void importProfile(String aDisplayName,
+ Applicability aApplicability,
+ InputStream aInput)
+ throws SPIException;
+
+ /**
+ * Returns the requested profile or null if it does
+ * not exist.
+ *
+ * @param aId id for the required profile
+ * @return object representing profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Profile getProfile(String aId) throws SPIException;
+
+ /**
+ * Returns the profiles that match the filter string.
+ *
+ * @param aApplicability scope of profiles required
+ * @return <code>Iterator</code> of profiles matching
+ * the filter
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Iterator getProfiles(Applicability aApplicability)
+ throws SPIException;
+
+ /**
+ * Returns a boolean indicating if the current user has read only
+ * access for this profile repository.
+ *
+ * @return <code>true</code> if the current user has
+ * read only access
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public boolean isReadOnly() throws SPIException;
+
+ /**
+ * Returns the id for this profile repository.
+ *
+ * @return id for this repository
+ */
+ public String getId();
+
+ /**
+ * Finds a profile object given its displayname
+ *
+ * @param aDisplayName display name for profile
+ * @return object representing the profile
+ * or null if not found
+ * @throws <code>SPIException/code> if error
+ * occurs
+ */
+ public Profile findProfile(String aDisplayName) throws SPIException;
+
+ /**
+ * Returns the container entity.
+ *
+ * @return the container entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public Entity getEntity() throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileRepositoryImpl.java b/src/com/sun/apoc/spi/profiles/ProfileRepositoryImpl.java
new file mode 100644
index 0000000..53fdce7
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileRepositoryImpl.java
@@ -0,0 +1,263 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.profiles;
+
+import com.sun.apoc.spi.PolicySource;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.TreeSet;
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.util.ImporterExporter;
+import com.sun.apoc.spi.util.ZipImporterExporter;
+/**
+ * Abstract class for a profile repository.
+ *
+ */
+public abstract class ProfileRepositoryImpl implements ProfileRepository
+{
+ protected String mEntityId;
+ protected String mId;
+ protected PolicySource mPolicySource;
+
+ public PolicySource getPolicySource() {
+ return mPolicySource;
+ }
+
+ /**
+ * returns the maximum priority assigned to the profiles
+ * contained in this repository and with the specified scope
+ *
+ * @param aApplicability scope of the profiles
+ * @return maximum priority in use
+ * @throws SPIException if error occurs
+ */
+ public int getMaxPriority (Applicability aApplicability)
+ throws SPIException {
+ int highestPriority = 0;
+ Iterator profiles = getProfiles(aApplicability);
+ while (profiles.hasNext()) {
+ Profile profile = (Profile)profiles.next();
+ int priority = profile.getPriority();
+ if (priority > highestPriority) {
+ highestPriority = priority;
+ }
+ }
+ return highestPriority;
+ }
+
+ /**
+ * Finds a profile object given its displayname
+ *
+ * @param aDisplayName display name for profile
+ * @return object representing the profile
+ * or null if not found
+ * @throws <code>SPIException/code> if error
+ * occurs
+ */
+ public abstract Profile findProfile(String aDisplayName)
+ throws SPIException;
+
+ /**
+ * Creates and returns a <code>Profile</code> object.
+ *
+ * @param aDisplayName the display name for the profile
+ * @param aApplicability applicablity of profile
+ * @return <code>Profile</code> object
+ * @throws SPIException if error occurs
+ * @throws InvalidDisplayNameException if aDisplayName is null
+ * @throws UnknownApplicabilityException if aApplicability is unknown
+ */
+ public Profile createProfile(String aDisplayName,
+ Applicability aApplicability)
+ throws SPIException {
+ if ((aDisplayName == null) || (aDisplayName.length() == 0)) {
+ throw new InvalidDisplayNameException();
+ }
+ if (aApplicability.equals(Applicability.UNKNOWN)) {
+ throw new UnknownApplicabilityException();
+ }
+ int priority = getMaxPriority(aApplicability) + 1;
+ return createTheProfile(aDisplayName, aApplicability, priority);
+ }
+
+ protected abstract Profile createTheProfile (String aDisplayName,
+ Applicability aApplicability,
+ int priority)
+ throws SPIException;
+
+ /**
+ * Deletes a <code>Profile</code> object.
+ *
+ * @param aProfile the <code>Profile</code> object
+ * @throws SPIException if error occurs
+ * @throws InvalidProfileException if aProfile
+ * is assigned to entities
+ */
+ public void destroyProfile(Profile aProfile)
+ throws SPIException {
+ // Check if the profile is assigned to an entity.
+ if (aProfile.hasAssignedEntities()) {
+ throw new InvalidProfileException(
+ InvalidProfileException.ASSIGNED_PROFILE_KEY);
+ }
+ deleteProfile( aProfile );
+ }
+
+ /**
+ * Exports a <code>Profile</code> object.
+ *
+ * @param aProfile the <code>Profile</code> object
+ * @param aOutput output stream
+ * @throws SPIException if error occurs
+ * @throws NullProfileException if aProfile is null
+ * @throws ProfileStreamException if aOutput is null
+ */
+ public void exportProfile(Profile aProfile,
+ OutputStream aOutput)
+ throws SPIException {
+ if (aProfile == null) {
+ throw new NullProfileException();
+ }
+ if (aOutput == null) {
+ throw new ProfileStreamException(
+ ProfileStreamException.NULL_STREAM_KEY);
+ }
+ ImporterExporter exporter = new ZipImporterExporter();
+ exporter.exportProfile(aProfile, aOutput);
+ }
+
+ /**
+ * Imports a profile from a stream in default format.
+ *
+ * @param aDisplayName display name for profile
+ * @param aApplicability scope
+ * @param aInput stream from which the profile will
+ * be imported
+ * @throws SPIException if an error occurs.
+ * @throws InvalidDisplayNameException if aDisplayName is null
+ * @throws UnknownApplicabilityException if aApplicability is unknown
+ * @throws ProfileStreamException if aInput is null
+ */
+ public void importProfile(String aDisplayName,
+ Applicability aApplicability,
+ InputStream aInput)
+ throws SPIException {
+ if ((aDisplayName == null) || (aDisplayName.length() == 0)) {
+ throw new InvalidDisplayNameException();
+ }
+ if (aApplicability != null && aApplicability.equals(Applicability.UNKNOWN)) {
+ throw new UnknownApplicabilityException();
+ }
+ if (aInput == null) {
+ throw new ProfileStreamException(
+ ProfileStreamException.NULL_STREAM_KEY);
+ }
+ ImporterExporter importer = new ZipImporterExporter();
+ importer.importProfile(this, aDisplayName, aApplicability,
+ aInput);
+ }
+
+ /**
+ * Returns the requested profile or null if it does
+ * not exist.
+ *
+ * @param aId id for the required profile
+ * @return object representing profile
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Profile getProfile(String aId)
+ throws SPIException;
+
+ /**
+ * Returns the profiles that match the filter string.
+ *
+ * @param aApplicability scope of profiles required
+ * @return <code>Iterator</code> of profiles matching
+ * the filter
+ * @throws SPIException if error occurs
+ * @throws UnknownApplicabilityException if aApplicability is unknown
+ */
+ public Iterator getProfiles(Applicability aApplicability)
+ throws SPIException {
+ if (aApplicability.equals(Applicability.UNKNOWN)) {
+ throw new UnknownApplicabilityException();
+ }
+ return getTheProfiles(aApplicability).iterator();
+ }
+
+ protected abstract TreeSet getTheProfiles (Applicability aApplicability)
+ throws SPIException;
+
+ /**
+ * Returns a boolean indicating if the current user has read only
+ * access for this profile repository.
+ *
+ * @return <code>true</code> if the current user has
+ * read only access
+ * otherwise <code>false</code>
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract boolean isReadOnly() throws SPIException;
+
+ /**
+ * Returns the id for this profile repository.
+ *
+ * @return id for this repository
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the container entity.
+ *
+ * @return the container entity
+ * @throws <code>SPIException</code> if error occurs
+ */
+ public abstract Entity getEntity() throws SPIException;
+
+
+ /**
+ * Deletes the profile <code>aProfile</code> from the repository
+ *
+ * @param aProfile the <code>Profile</code> object
+ * @throws <code>SPIException</code> if error occurs
+ */
+ protected abstract void deleteProfile( Profile aProfile )
+ throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileStreamException.java b/src/com/sun/apoc/spi/profiles/ProfileStreamException.java
new file mode 100644
index 0000000..868ac31
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileStreamException.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+public class ProfileStreamException extends ProfileException {
+
+ public static final String NULL_STREAM_KEY =
+ "error.spi.profile.stream.null";
+ public static final String EMPTY_STREAM_KEY =
+ "error.spi.profile.stream.empty";
+ public static final String ERROR_STREAM_KEY =
+ "error.spi.profile.stream.error";
+
+ public ProfileStreamException () {
+ super();
+ }
+
+ public ProfileStreamException (String messageKey) {
+ super();
+ mMessageKey = messageKey;
+ }
+
+ public ProfileStreamException (String messageKey, Throwable cause) {
+ super(cause);
+ mMessageKey = messageKey;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/profiles/ProfileZipException.java b/src/com/sun/apoc/spi/profiles/ProfileZipException.java
new file mode 100644
index 0000000..32a333a
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ProfileZipException.java
@@ -0,0 +1,52 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+public class ProfileZipException extends ProfileException {
+
+ private static final String ZIP_PROFILE_KEY =
+ "error.spi.profile.zip";
+
+ public ProfileZipException () {
+ super();
+ mMessageKey = ZIP_PROFILE_KEY;
+ }
+
+ public ProfileZipException (Throwable cause) {
+ super(cause);
+ mMessageKey = ZIP_PROFILE_KEY;
+ }
+
+}
diff --git a/src/com/sun/apoc/spi/profiles/UnknownApplicabilityException.java b/src/com/sun/apoc/spi/profiles/UnknownApplicabilityException.java
new file mode 100644
index 0000000..21eefb6
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/UnknownApplicabilityException.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.profiles;
+
+public class UnknownApplicabilityException extends ProfileException {
+
+ private static final String UNKNOWN_APPLICABILITY_KEY =
+ "error.spi.profile.applicability.unknown";
+
+ protected String mDisplayName = null;
+
+ public UnknownApplicabilityException () {
+ super();
+ mMessageKey = UNKNOWN_APPLICABILITY_KEY;
+ }
+}
diff --git a/src/com/sun/apoc/spi/profiles/ZipProfileReadWrite.java b/src/com/sun/apoc/spi/profiles/ZipProfileReadWrite.java
new file mode 100644
index 0000000..3bd7262
--- /dev/null
+++ b/src/com/sun/apoc/spi/profiles/ZipProfileReadWrite.java
@@ -0,0 +1,282 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.profiles;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.policies.Policy;
+
+
+/**
+ * Implementation of the Profile read/write in ZIP file format.
+ *
+ * Policies are stored as xml files where each file represents one single
+ * component. The content of each file is the XML-bob of the policy. In
+ * addition, the first entry of each zip file corresponds to the meta
+ * configuration data such as display name, applicability, etc.
+ *
+ * In APOC 1.x versions the format of the zip file was slightly different. Here
+ * policies are stored in a tree structure where each item of the
+ * component name is a subdirectory and the policy itself is stored
+ * in a file named after the last item. The whole tree is then zipped
+ * into a single file. The tree structure is identical to the one found
+ * in the registry/data repositories in an office installation.
+ *
+ * As an example, if the profile contains org.openoffice.Inet and
+ * org.openoffice.Office.Common, the ZIP file will contain two entries
+ * (old format):
+ * - org/openoffice/Inet.xcu (containing the policy data) and
+ * - org/openoffice/Office/Common.xcu (containing the policy data)
+ *
+ * Or using the new format it will contain:
+ * - META-INF/general.properties (containing the meta configuration data)
+ * - org.openoffice.Inet.xml (containing the policy data) and
+ * - org.openoffice.Office.Common.xml (containing the policy data)
+ */
+public class ZipProfileReadWrite {
+ /**
+ * The current product version
+ */
+ public static final String PRODUCT_VERSION = "2.0";
+
+ /**
+ * Constants for accessing/storing the meta configuration data
+ */
+ public static final String APOC_VERSION = "ApocVersion";
+ public static final String DISPLAY_NAME = "DisplayName";
+ public static final String COMMENT = "Comment";
+ public static final String APPLICABILITY = "Applicability";
+ public static final String PRIORITY = "Priority";
+ public static final String AUTHOR = "Author";
+ public static final String LAST_MODIFIED = "LastModified";
+
+ /**
+ * The zip file entry for storing the meta configuration data
+ */
+ public static final String META_INF_ENTRY = "META-INF/general.properties";
+
+ /**
+ * Suffix appended to entries holding policy data.
+ */
+ public static final String ENTRY_SUFFIX = ".xml";
+
+ /**
+ * Encoding of the policy data in the entries.
+ */
+ public static final String ENTRY_ENCODING = "UTF-8";
+
+ /**
+ * Component items separator as a character.
+ */
+ public static final char COMPONENT_SEPARATOR = '.';
+
+ /**
+ * Entry components separator.
+ */
+ public static final char ENTRY_SEPARATOR = '/';
+
+ /**
+ * Old suffix appended to entries holding policy data.
+ */
+ public static final String OLD_ENTRY_SUFFIX = ".xcu";
+
+
+
+ /**
+ * Writes the meta configuration data of a given profile to a stream.
+ *
+ * @param aProfile profile identifier
+ * @param aOutput stream for exported data
+ * @throws SPIException if an error occurs.
+ */
+ public static void writeMetaData(Profile aProfile,
+ ZipOutputStream aOutput) throws IOException, SPIException {
+ // collect all the meta data information
+ Properties metaData = new Properties();
+ metaData.put(APOC_VERSION, PRODUCT_VERSION);
+ metaData.put(DISPLAY_NAME, aProfile.getDisplayName());
+ metaData.put(COMMENT, aProfile.getComment());
+ metaData.put(AUTHOR, aProfile.getAuthor());
+ metaData.put(PRIORITY, new Integer(aProfile.getPriority()).toString());
+ metaData.put(APPLICABILITY, aProfile.getApplicability().getStringValue());
+ metaData.put(LAST_MODIFIED, Long.toString(aProfile.getLastModified()));
+
+ // create new zip entry
+ ZipEntry entry = new ZipEntry(META_INF_ENTRY);
+ aOutput.putNextEntry(entry);
+
+ // store the meta data information
+ metaData.store(aOutput, null);
+ aOutput.closeEntry();
+ }
+
+ /**
+ * Actual export of policies from the specified profile.
+ * The policy names are transformed into ZIP entry names and the
+ * policy data becomes the content of the entry.
+ *
+ * @param aProfile profile identifier
+ * @param aOutput stream to export the data to
+ * @throws SPIException if an IO error occurs.
+ * @throws ProfileZipException if an error occurs
+ * @throws ProfileStreamException if an error occurs
+ */
+ public static void writePolicies(Profile aProfile, ZipOutputStream aOutput)
+ throws IOException, SPIException {
+ Iterator it = aProfile.getPolicies();
+ while (it.hasNext()) {
+ Policy policy = (Policy) it.next();
+ StringBuffer buffer = new StringBuffer(policy.getId());
+ buffer.append(ENTRY_SUFFIX);
+
+ // create new zip entry for each policy
+ ZipEntry entry = new ZipEntry(buffer.toString());
+ entry.setTime(policy.getLastModified());
+ aOutput.putNextEntry(entry);
+
+ // and store the content of the policy
+ byte[] data = policy.getData().getBytes(ENTRY_ENCODING);
+ aOutput.write(data, 0, data.length);
+ aOutput.closeEntry();
+ }
+ }
+
+ /**
+ * Reads the meta configuration data from a stream.
+ *
+ * @param aInput stream for inported data
+ */
+ public static Properties readMetaData(ZipInputStream aInput)
+ throws IOException {
+ Properties metaData = null;
+ ZipEntry entry = aInput.getNextEntry();
+ if (entry != null) {
+ if (entry.getName().equals(META_INF_ENTRY)) {
+ metaData = new Properties();
+ metaData.load(aInput);
+ aInput.closeEntry();
+ }
+ }
+ return metaData;
+ }
+
+ /**
+ * Reads the policies from a stream.
+ *
+ * @param aInput stream for inported data
+ */
+ public static Iterator readPolicies(ZipInputStream aInput)
+ throws IOException {
+ ArrayList policies = new ArrayList();
+ ZipEntry entry = aInput.getNextEntry();
+ while (entry != null) {
+ // determine policy name
+ String name = entry.getName();
+ int pos = name.indexOf(ENTRY_SUFFIX);
+ if (pos > 0) {
+ name = name.substring(0, pos);
+
+ // retrieve policy data
+ byte[] buffer = new byte[1024] ;
+ StringBuffer data = new StringBuffer();
+ while (aInput.available() != 0) {
+ int bytesRead = aInput.read(buffer, 0, buffer.length);
+ if (bytesRead > 0) {
+ data.append(new String(buffer, 0, bytesRead, ENTRY_ENCODING));
+ }
+ }
+ Policy policy = new Policy(name, data.toString(), entry.getTime());
+ policies.add(policy);
+ }
+
+ aInput.closeEntry() ;
+ entry = aInput.getNextEntry() ;
+ }
+ return policies.iterator();
+ }
+
+
+ /**
+ * Actual import of policy data (old format) from a ZIP file.
+ *
+ * Note: in that case, the first ZipEntry has already been read
+ * before this method is called by importProfile
+ * (in readMetaConfigurationData) but it will always be a directory
+ * because every policy is stored in at least one-level deep directory
+ * and directories are skipped by this method so no useful data is lost.
+ *
+ * @param aInput stream containing the zipped data
+ * @throws SPIException if an IO error occurs.
+ * @throws ProfileZipException if an error occurs
+ * @throws ProfileStreamException if an error occurs
+ */
+ public static Iterator readOldPoliciesFormat(ZipInputStream aInput)
+ throws IOException {
+ ArrayList policies = new ArrayList();
+ ZipEntry entry = aInput.getNextEntry() ;
+ while (entry != null) {
+ if (!entry.isDirectory()) {
+ String name = entry.getName() ;
+ int usefulSize = name.length() - OLD_ENTRY_SUFFIX.length();
+ if (!(usefulSize <= 0 ||
+ !name.substring(usefulSize).equals(OLD_ENTRY_SUFFIX))) {
+ name = name.substring(0, usefulSize).replace(ENTRY_SEPARATOR,
+ COMPONENT_SEPARATOR);
+ byte [] buffer = new byte[1024] ;
+ StringBuffer data = new StringBuffer();
+ while (aInput.available() != 0) {
+ int bytesRead = aInput.read(buffer, 0, buffer.length);
+ if (bytesRead > 0) {
+ data.append(new String(buffer, 0, bytesRead, ENTRY_ENCODING));
+ }
+ }
+ Policy policy = new Policy(name, data.toString());
+ policies.add(policy);
+ }
+ }
+ aInput.closeEntry() ;
+ entry = aInput.getNextEntry() ;
+ }
+ return policies.iterator();
+ }
+}
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors.properties b/src/com/sun/apoc/spi/resources/SPIErrors.properties
new file mode 100644
index 0000000..7f120b6
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors.properties
@@ -0,0 +1,135 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2007/01/17 14:49:06 $ $Revision: 1.9 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = An internal error occured
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = The parameter {0} is causing an error.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = The parameter {0} is causing an error, the value must be comprised in {1}.
+error.spi.environment.parameter.missing = The parameter {0} is missing.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = The parameter {0} is missing, the value must be comprised in {1}.
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = The parameter {0} ({1}) is not valid.
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = The parameter {0} ({1}) is not valid, the value must be comprised in {2}.
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = Error on reading the configuration data in file {0}.
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = Error on reading the configuration data on LDAP server {0}.
+error.spi.environment.remote.ldap.invalid = The configuration data on LDAP server {0} is invalid.
+error.spi.environment.remote.metaconf.invalid = The LDAP metaconfiguration data is invalid.
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = Error loading class {0}.
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = A profile of Applicability {0} cannot be assigned to the entity {1}.
+
+# Illegal Access
+error.spi.access.illegal.read = The data cannot be read.
+error.spi.access.illegal.read.ldap = The LDAP data cannot be read.
+error.spi.access.illegal.read.file = The file data cannot be read.
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = The data cannot be read in file {0}.
+error.spi.access.illegal.read.ldap.size = The number of entries to process on the LDAP server is larger than the server limit.
+error.spi.access.illegal.write = The data cannot be written.
+error.spi.access.illegal.write.ldap = The LDAP data cannot be written.
+error.spi.access.illegal.write.file = The file data cannot be written.
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = The file {0} cannot be created.
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = A connection error occured with URL {0}.
+error.spi.connection.open = An error occured while connecting to {0}.
+error.spi.connection.close = An error occured while closing the connection to {0}.
+error.spi.connection.interrupted = The connection to {0} has been interrupted.
+# {1} is a number (size limit)
+error.spi.connection.size = Connection to {0} is not able to set size limit to {1}.
+# {1} is the user name
+error.spi.connection.authentication = An authentication error occured while connecting the user {1} to {0}.
+# {1} is the user name
+error.spi.connection.authentication.notallowed = The user {1} is not allowed to connect to {0}.
+
+# Entity
+error.spi.entity.filter.null = The filter used for the research is null.
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = The filter used for the research ({0}) is invalid.
+# {0} is the id of the entity
+error.spi.entity.noexist = The entity {0} does not exist.
+
+# Profile
+error.spi.profile.name.null = The profile display name is null.
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = The profile display name ({0}) is invalid.
+# {0} is the id of the profile
+error.spi.profile.invalid.id = The profile id {0} is invalid.
+
+error.spi.profile.applicability.unknown = An applicability of type unknown is not valid.
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = The priority ({0,number,integer}) is already in use.
+error.spi.profile.priority.invalid = The priority ({0,number,integer}) is invalid.
+
+error.spi.profile.invalid = The profile is invalid.
+error.spi.profile.invalid.assigned = The profile is assigned to entities.
+error.spi.profile.invalid.empty = The profile does not contain any policy.
+# {0} id of the profile
+error.spi.profile.invalid.noexist = The profile ({0}) does not exist.
+error.spi.profile.null = The profile is null.
+
+error.spi.profile.stream.null = The stream is null.
+error.spi.profile.stream.empty = The source does not contain any valid data.
+error.spi.profile.stream.error = Error on the stream for the profile data.
+error.spi.profile.zip = Zip error on profile data.
+error.spi.profile.import = The selected profile has applicability {0} and cannot be imported as a {1} profile.
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = The policy {0} does not exist.
+error.spi.policy.null = The policy is null.
+error.spi.policies.null = The set of policies is null or empty.
+error.spi.policy.mismatch = Policy ids do not match.
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = The {0} {1} is mandatory.
+error.spi.policytree.element.mandatory.noremove = The {0} {1} is mandatory, cannot be removed.
+error.spi.policytree.element.readonly = The {0} {1} is read-only.
+error.spi.policytree.element.copy = Cannot create copy of {0} {1}.
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = DataType {0} is invalid.
+
+error.spi.policytree.policynode.invalid = The PolicyNode is invalid.
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = The PolicyNode {0} is incompatible with policy {1}.
+error.spi.policytree.policynode.name.invalid = The PolicyNode name ({0}) is invalid.
+
+error.spi.policytree.property.invalid = The Property is invalid.
+error.spi.policytree.property.value.invalid = The Property value is invalid.
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = The Property {0} cannot be set to nil.
+error.spi.policytree.property.name.invalid = The Property name ({0}) is invalid.
+
+error.spi.policytree.xml = An XML parsing error occured.
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_de.properties b/src/com/sun/apoc/spi/resources/SPIErrors_de.properties
new file mode 100644
index 0000000..26cfd49
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_de.properties
@@ -0,0 +1,134 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_de.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2006/02/24 14:55:04 $ $Revision: 1.1 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = Ein interner Fehler ist aufgetreten.
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = Der Parameter {0} verursacht einen Fehler.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = Der Parameter {0} verursacht einen Fehler. Der Wert muss in {1} enthalten sein.
+error.spi.environment.parameter.missing = Der Parameter {0} fehlt.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = Der Parameter {0} fehlt. Der Wert muss in {1} enthalten sein.
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = Der Parameter {0} ({1}) ist ungültig.
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = Der Parameter {0} ({1}) ist ungültig. Der Wert muss in {2} enthalten sein.
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = Fehler beim Lesen der Konfigurationsdaten in der Datei {0}.
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = Fehler beim Lesen der Konfigurationsdaten auf dem LDAP-Server {0}.
+error.spi.environment.remote.ldap.invalid = Die Konfigurationsdaten auf dem LDAP-Server {0} sind ungültig.
+error.spi.environment.remote.metaconf.invalid = Die LDAP-Daten für die Metakonfiguration sind ungültig.
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = Fehler beim Laden der Klasse {0}.
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = Der Entität {1} kann kein Anwendbarkeitsprofil {0} zugewiesen werden.
+
+# Illegal Access
+error.spi.access.illegal.read = Die Daten können nicht gelesen werden.
+error.spi.access.illegal.read.ldap = Die LDAP-Daten können nicht gelesen werden.
+error.spi.access.illegal.read.file = Die Dateidaten können nicht gelesen werden.
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = Die Daten in Datei {0} können nicht gelesen werden.
+error.spi.access.illegal.read.ldap.size = Die Anzahl zu verarbeitender Einträge überschreitet das LDAP-Serverlimit.
+error.spi.access.illegal.write = Die Daten können nicht geschrieben werden.
+error.spi.access.illegal.write.ldap = Die LDAP-Daten können nicht geschrieben werden.
+error.spi.access.illegal.write.file = Die Dateidaten können nicht geschrieben werden.
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = Die Datei {0} kann nicht erstellt werden.
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = Für die URL {0} ist ein Verbindungsfehler aufgetreten.
+error.spi.connection.open = Beim Herstellen der Verbindung mit {0} ist ein Fehler aufgetreten.
+error.spi.connection.close = Beim Beenden der Verbindung zu {0} ist ein Fehler aufgetreten.
+error.spi.connection.interrupted = Die Verbindung mit {0} wurde unterbrochen.
+# {1} is a number (size limit)
+error.spi.connection.size = Für die Verbindung mit {0} kann die Maximalgröße nicht auf {1} eingestellt werden.
+# {1} is the user name
+error.spi.connection.authentication = Beim Herstellen der Verbindung mit {0} durch den Benutzer {1} ist ein Authentifizierungsfehler aufgetreten.
+# {1} is the user name
+error.spi.connection.authentication.notallowed = Der Benutzer {1} ist nicht berechtigt, eine Verbindung mit {0} herzustellen.
+
+# Entity
+error.spi.entity.filter.null = Der verwendete Suchfilter ist ungültig.
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = Der verwendete Suchfilter ({0}) ist ungültig.
+# {0} is the id of the entity
+error.spi.entity.noexist = Die Entität {0} ist nicht vorhanden.
+
+# Profile
+error.spi.profile.name.null = Der Anzeigename des Profils ist ungültig.
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = Der Anzeigename des Profils ({0}) ist ungültig.
+# {0} is the id of the profile
+error.spi.profile.invalid.id = Die Profilkennung {0} ist ungültig.
+
+error.spi.profile.applicability.unknown = Eine Anwendbarkeit vom Typ 'Unbekannt' ist ungültig.
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = Die Priorität ({0,number,integer}) wird bereits verwendet.
+error.spi.profile.priority.invalid = Die Priorität ({0,number,integer}) ist ungültig.
+
+error.spi.profile.invalid = Das Profil ist ungültig.
+error.spi.profile.invalid.assigned = Das Profil ist Entitäten zugewiesen.
+error.spi.profile.invalid.empty = Das Profil enthält keine Richtlinie.
+# {0} id of the profile
+error.spi.profile.invalid.noexist = Das Profil ({0}) ist nicht vorhanden.
+error.spi.profile.null = Das Profil ist ungültig.
+
+error.spi.profile.stream.null = Der Datenstrom ist ungültig.
+error.spi.profile.stream.empty = Die Quelle enthält keine gültigen Daten.
+error.spi.profile.stream.error = Im Datenstrom für die Profildaten ist ein Fehler aufgetreten.
+error.spi.profile.zip = In den Profildaten ist ein Zip-Fehler aufgetreten.
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = Die Richtlinie {0} ist nicht vorhanden.
+error.spi.policy.null = Die Richtlinie ist ungültig.
+error.spi.policies.null = Der Richtliniensatz ist ungültig oder leer.
+error.spi.policy.mismatch = Die Richtlinienkennungen stimmen nicht überein.
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = {0} {1} ist vorgeschrieben.
+error.spi.policytree.element.mandatory.noremove = {0} {1} ist vorgeschrieben und kann nicht entfernt werden.
+error.spi.policytree.element.readonly = {0} {1} ist schreibgeschützt.
+error.spi.policytree.element.copy = Es kann keine Kopie von {0} {1} erstellt werden.
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = Der Datentyp {0} ist ungültig.
+
+error.spi.policytree.policynode.invalid = Der Richtlinienknoten ist ungültig.
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = Der Richtlinienknoten {0} ist ungültig und nicht mit der Richtlinie {1} kompatibel.
+error.spi.policytree.policynode.name.invalid = Der Richtlinienknoten-Name ({0}) ist ungültig.
+
+error.spi.policytree.property.invalid = Die Eigenschaft ist ungültig.
+error.spi.policytree.property.value.invalid = Der Wert für die Eigenschaft ist ungültig.
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = Die Eigenschaft {0} kann nicht auf Null gesetzt werden.
+error.spi.policytree.property.name.invalid = Der Eigenschaftenname ({0}) ist ungültig.
+
+error.spi.policytree.xml = Es ist ein XML-Parse-Fehler aufgetreten.
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_en.properties b/src/com/sun/apoc/spi/resources/SPIErrors_en.properties
new file mode 100644
index 0000000..5b7c45b
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_en.properties
@@ -0,0 +1,135 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_en.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2007/01/17 14:49:06 $ $Revision: 1.2 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = An internal error occured
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = The parameter {0} is causing an error.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = The parameter {0} is causing an error, the value must be comprised in {1}.
+error.spi.environment.parameter.missing = The parameter {0} is missing.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = The parameter {0} is missing, the value must be comprised in {1}.
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = The parameter {0} ({1}) is not valid.
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = The parameter {0} ({1}) is not valid, the value must be comprised in {2}.
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = Error on reading the configuration data in file {0}.
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = Error on reading the configuration data on LDAP server {0}.
+error.spi.environment.remote.ldap.invalid = The configuration data on LDAP server {0} is invalid.
+error.spi.environment.remote.metaconf.invalid = The LDAP metaconfiguration data is invalid.
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = Error loading class {0}.
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = A profile of Applicability {0} cannot be assigned to the entity {1}.
+
+# Illegal Access
+error.spi.access.illegal.read = The data cannot be read.
+error.spi.access.illegal.read.ldap = The LDAP data cannot be read.
+error.spi.access.illegal.read.file = The file data cannot be read.
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = The data cannot be read in file {0}.
+error.spi.access.illegal.read.ldap.size = The number of entries to process on the LDAP server is larger than the server limit.
+error.spi.access.illegal.write = The data cannot be written.
+error.spi.access.illegal.write.ldap = The LDAP data cannot be written.
+error.spi.access.illegal.write.file = The file data cannot be written.
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = The file {0} cannot be created.
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = A connection error occured with URL {0}.
+error.spi.connection.open = An error occured while connecting to {0}.
+error.spi.connection.close = An error occured while closing the connection to {0}.
+error.spi.connection.interrupted = The connection to {0} has been interrupted.
+# {1} is a number (size limit)
+error.spi.connection.size = Connection to {0} is not able to set size limit to {1}.
+# {1} is the user name
+error.spi.connection.authentication = An authentication error occured while connecting the user {1} to {0}.
+# {1} is the user name
+error.spi.connection.authentication.notallowed = The user {1} is not allowed to connect to {0}.
+
+# Entity
+error.spi.entity.filter.null = The filter used for the research is null.
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = The filter used for the research ({0}) is invalid.
+# {0} is the id of the entity
+error.spi.entity.noexist = The entity {0} does not exist.
+
+# Profile
+error.spi.profile.name.null = The profile display name is null.
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = The profile display name ({0}) is invalid.
+# {0} is the id of the profile
+error.spi.profile.invalid.id = The profile id {0} is invalid.
+
+error.spi.profile.applicability.unknown = An applicability of type unknown is not valid.
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = The priority ({0,number,integer}) is already in use.
+error.spi.profile.priority.invalid = The priority ({0,number,integer}) is invalid.
+
+error.spi.profile.invalid = The profile is invalid.
+error.spi.profile.invalid.assigned = The profile is assigned to entities.
+error.spi.profile.invalid.empty = The profile does not contain any policy.
+# {0} id of the profile
+error.spi.profile.invalid.noexist = The profile ({0}) does not exist.
+error.spi.profile.null = The profile is null.
+
+error.spi.profile.stream.null = The stream is null.
+error.spi.profile.stream.empty = The source does not contain any valid data.
+error.spi.profile.stream.error = Error on the stream for the profile data.
+error.spi.profile.zip = Zip error on profile data.
+error.spi.profile.import = The selected profile has applicability {0} and cannot be imported as a {1} profile.
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = The policy {0} does not exist.
+error.spi.policy.null = The policy is null.
+error.spi.policies.null = The set of policies is null or empty.
+error.spi.policy.mismatch = Policy ids do not match.
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = The {0} {1} is mandatory.
+error.spi.policytree.element.mandatory.noremove = The {0} {1} is mandatory, cannot be removed.
+error.spi.policytree.element.readonly = The {0} {1} is read-only.
+error.spi.policytree.element.copy = Cannot create copy of {0} {1}.
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = DataType {0} is invalid.
+
+error.spi.policytree.policynode.invalid = The PolicyNode is invalid.
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = The PolicyNode {0} is incompatible with policy {1}.
+error.spi.policytree.policynode.name.invalid = The PolicyNode name ({0}) is invalid.
+
+error.spi.policytree.property.invalid = The Property is invalid.
+error.spi.policytree.property.value.invalid = The Property value is invalid.
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = The Property {0} cannot be set to nil.
+error.spi.policytree.property.name.invalid = The Property name ({0}) is invalid.
+
+error.spi.policytree.xml = An XML parsing error occured.
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_en_US.properties b/src/com/sun/apoc/spi/resources/SPIErrors_en_US.properties
new file mode 100644
index 0000000..e52ed94
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_en_US.properties
@@ -0,0 +1,135 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_en_US.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2007/01/17 14:49:07 $ $Revision: 1.2 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = An internal error occured
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = The parameter {0} is causing an error.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = The parameter {0} is causing an error, the value must be comprised in {1}.
+error.spi.environment.parameter.missing = The parameter {0} is missing.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = The parameter {0} is missing, the value must be comprised in {1}.
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = The parameter {0} ({1}) is not valid.
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = The parameter {0} ({1}) is not valid, the value must be comprised in {2}.
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = Error on reading the configuration data in file {0}.
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = Error on reading the configuration data on LDAP server {0}.
+error.spi.environment.remote.ldap.invalid = The configuration data on LDAP server {0} is invalid.
+error.spi.environment.remote.metaconf.invalid = The LDAP metaconfiguration data is invalid.
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = Error loading class {0}.
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = A profile of Applicability {0} cannot be assigned to the entity {1}.
+
+# Illegal Access
+error.spi.access.illegal.read = The data cannot be read.
+error.spi.access.illegal.read.ldap = The LDAP data cannot be read.
+error.spi.access.illegal.read.file = The file data cannot be read.
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = The data cannot be read in file {0}.
+error.spi.access.illegal.read.ldap.size = The number of entries to process on the LDAP server is larger than the server limit.
+error.spi.access.illegal.write = The data cannot be written.
+error.spi.access.illegal.write.ldap = The LDAP data cannot be written.
+error.spi.access.illegal.write.file = The file data cannot be written.
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = The file {0} cannot be created.
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = A connection error occured with URL {0}.
+error.spi.connection.open = An error occured while connecting to {0}.
+error.spi.connection.close = An error occured while closing the connection to {0}.
+error.spi.connection.interrupted = The connection to {0} has been interrupted.
+# {1} is a number (size limit)
+error.spi.connection.size = Connection to {0} is not able to set size limit to {1}.
+# {1} is the user name
+error.spi.connection.authentication = An authentication error occured while connecting the user {1} to {0}.
+# {1} is the user name
+error.spi.connection.authentication.notallowed = The user {1} is not allowed to connect to {0}.
+
+# Entity
+error.spi.entity.filter.null = The filter used for the research is null.
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = The filter used for the research ({0}) is invalid.
+# {0} is the id of the entity
+error.spi.entity.noexist = The entity {0} does not exist.
+
+# Profile
+error.spi.profile.name.null = The profile display name is null.
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = The profile display name ({0}) is invalid.
+# {0} is the id of the profile
+error.spi.profile.invalid.id = The profile id {0} is invalid.
+
+error.spi.profile.applicability.unknown = An applicability of type unknown is not valid.
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = The priority ({0,number,integer}) is already in use.
+error.spi.profile.priority.invalid = The priority ({0,number,integer}) is invalid.
+
+error.spi.profile.invalid = The profile is invalid.
+error.spi.profile.invalid.assigned = The profile is assigned to entities.
+error.spi.profile.invalid.empty = The profile does not contain any policy.
+# {0} id of the profile
+error.spi.profile.invalid.noexist = The profile ({0}) does not exist.
+error.spi.profile.null = The profile is null.
+
+error.spi.profile.stream.null = The stream is null.
+error.spi.profile.stream.empty = The source does not contain any valid data.
+error.spi.profile.stream.error = Error on the stream for the profile data.
+error.spi.profile.zip = Zip error on profile data.
+error.spi.profile.import = The selected profile has applicability {0} and cannot be imported as a {1} profile.
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = The policy {0} does not exist.
+error.spi.policy.null = The policy is null.
+error.spi.policies.null = The set of policies is null or empty.
+error.spi.policy.mismatch = Policy ids do not match.
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = The {0} {1} is mandatory.
+error.spi.policytree.element.mandatory.noremove = The {0} {1} is mandatory, cannot be removed.
+error.spi.policytree.element.readonly = The {0} {1} is read-only.
+error.spi.policytree.element.copy = Cannot create copy of {0} {1}.
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = DataType {0} is invalid.
+
+error.spi.policytree.policynode.invalid = The PolicyNode is invalid.
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = The PolicyNode {0} is incompatible with policy {1}.
+error.spi.policytree.policynode.name.invalid = The PolicyNode name ({0}) is invalid.
+
+error.spi.policytree.property.invalid = The Property is invalid.
+error.spi.policytree.property.value.invalid = The Property value is invalid.
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = The Property {0} cannot be set to nil.
+error.spi.policytree.property.name.invalid = The Property name ({0}) is invalid.
+
+error.spi.policytree.xml = An XML parsing error occured.
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_es.properties b/src/com/sun/apoc/spi/resources/SPIErrors_es.properties
new file mode 100644
index 0000000..a25f218
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_es.properties
@@ -0,0 +1,134 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_es.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2006/02/24 14:55:05 $ $Revision: 1.1 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = Ha habido un error interno.
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = El parámetro {0} está provocando un error.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = El parámetro {0} está provocando un error; el valor debe estar integrado en {1}.
+error.spi.environment.parameter.missing = No se encuentra el parámetro {0}.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = No se encuentra el parámetro {0}; el valor debe estar integrado en {1}.
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = El parámetro {0} ({1}) no es válido.
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = El parámetro {0} ({1}) no es válido, el valor debe estar integrado en {2}.
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = Error al leer los datos de configuración en el archivo {0}.
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = Error al leer los datos de configuración en el servidor LDAP {0}.
+error.spi.environment.remote.ldap.invalid = Los datos de configuración en el servidor LDAP {0} no son válidos.
+error.spi.environment.remote.metaconf.invalid = Los datos de la metaconfiguración LDAP no son válidos.
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = Error al cargar la clase {0}.
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = No se puede asignar un perfil de aplicabilidad {0} a la entidad {1}.
+
+# Illegal Access
+error.spi.access.illegal.read = No se pueden leer los datos.
+error.spi.access.illegal.read.ldap = No se pueden leer los datos LDAP.
+error.spi.access.illegal.read.file = No se pueden leer los datos del archivo.
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = No se pueden leer los datos del archivo {0}.
+error.spi.access.illegal.read.ldap.size = El número de entradas que procesar en el servidor LDAP es mayor que el límite del servidor.
+error.spi.access.illegal.write = No se pueden escribir los datos.
+error.spi.access.illegal.write.ldap = No se pueden escribir los datos LDAP.
+error.spi.access.illegal.write.file = No se pueden escribir los datos del archivo.
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = No se puede crear el archivo {0}.
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = Se ha producido un error de conexión con el URL {0}.
+error.spi.connection.open = Se ha producido un error durante la conexión con {0}.
+error.spi.connection.close = Se ha producido un error al cerrar la conexión con {0}.
+error.spi.connection.interrupted = Se ha interrumpido la conexión con {0}.
+# {1} is a number (size limit)
+error.spi.connection.size = La conexión con {0} no es capaz de establecer el límite de tamaño para {1}.
+# {1} is the user name
+error.spi.connection.authentication = Se ha producido un error de autenticación durante la conexión del usuario {1} con {0}.
+# {1} is the user name
+error.spi.connection.authentication.notallowed = No se permite al usuario {1} conectarse con {0}.
+
+# Entity
+error.spi.entity.filter.null = El filtro utilizado para la búsqueda es nulo.
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = El filtro utilizado para la búsqueda ({0}) no es válido.
+# {0} is the id of the entity
+error.spi.entity.noexist = La entidad {0} no existe.
+
+# Profile
+error.spi.profile.name.null = El nombre de visualización del perfil es nulo.
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = El nombre de visualización del perfil ({0}) no es válido.
+# {0} is the id of the profile
+error.spi.profile.invalid.id = El id del perfil {0} no es válido.
+
+error.spi.profile.applicability.unknown = Una aplicabilidad de tipo desconocido no es válida.
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = La prioridad ({0,número,entero}) ya se está utilizando.
+error.spi.profile.priority.invalid = La prioridad ({0,número,entero}) no es válida.
+
+error.spi.profile.invalid = El perfil no es válido.
+error.spi.profile.invalid.assigned = El perfil está asignado a entidades.
+error.spi.profile.invalid.empty = El perfil no contiene ninguna norma.
+# {0} id of the profile
+error.spi.profile.invalid.noexist = El perfil ({0}) no existe.
+error.spi.profile.null = El perfil es nulo.
+
+error.spi.profile.stream.null = El flujo es nulo.
+error.spi.profile.stream.empty = El origen no contiene datos válidos.
+error.spi.profile.stream.error = Error en el flujo de los datos del perfil.
+error.spi.profile.zip = Error de compresión de los datos del perfil.
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = La norma {0} no existe.
+error.spi.policy.null = La norma es nula.
+error.spi.policies.null = El conjunto de normas es nulo o está vacío.
+error.spi.policy.mismatch = Los id de normas no coinciden.
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = El {0} {1} es obligatorio.
+error.spi.policytree.element.mandatory.noremove = El {0} {1} es obligatorio, no se puede borrar.
+error.spi.policytree.element.readonly = El {0} {1} es de sólo lectura.
+error.spi.policytree.element.copy = No se puede crear una copia de {0} {1}.
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = El tipo de datos {0} no es válido.
+
+error.spi.policytree.policynode.invalid = El nodo de normas no es válido.
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = El nodo de normas {0} es incompatible con la norma {1}.
+error.spi.policytree.policynode.name.invalid = El nombre del nodo de normas ({0}) no es válido.
+
+error.spi.policytree.property.invalid = La propiedad no es válida.
+error.spi.policytree.property.value.invalid = El valor de la propiedad no es válido.
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = La propiedad {0} no se puede establecer como nula.
+error.spi.policytree.property.name.invalid = El nombre de la propiedad ({0}) no es válido.
+
+error.spi.policytree.xml = Se ha producido un error de análisis de XML.
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_fr.properties b/src/com/sun/apoc/spi/resources/SPIErrors_fr.properties
new file mode 100644
index 0000000..1cf0c31
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_fr.properties
@@ -0,0 +1,134 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_fr.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2006/12/01 15:10:44 $ $Revision: 1.2 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = Une erreur interne s'est produite.
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = Le paramètre {0} génère une erreur.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = Le paramètre {0} génère une erreur. Sa valeur doit être comprise dans la plage {1}.
+error.spi.environment.parameter.missing = Le paramètre {0} est manquant.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = Le paramètre {0} est manquant. Sa valeur doit être comprise dans la plage {1}.
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = Le paramètre {0} ({1}) n''est pas valide.
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = Le paramètre {0} ({1}) n''est pas valide. Sa valeur doit être comprise dans la plage {2}.
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = Erreur lors de la lecture des données de configuration du fichier {0}.
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = Erreur lors de la lecture des données de configuration du serveur LDAP {0}.
+error.spi.environment.remote.ldap.invalid = Les données de configuration du serveur LDAP {0} ne sont pas valides.
+error.spi.environment.remote.metaconf.invalid = Les données de métaconfiguration du serveur LDAP ne sont pas valides.
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = Erreur lors du chargement de la classe {0}.
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = Un profil avec les conditions d''applications {0} ne peut pas être assigné à l''entité {1}.
+
+# Illegal Access
+error.spi.access.illegal.read = Impossible de lire les données.
+error.spi.access.illegal.read.ldap = Impossible de lire les données du serveur LDAP.
+error.spi.access.illegal.read.file = Impossible de lire les données du fichier.
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = Impossible de lire les données du fichier {0}.
+error.spi.access.illegal.read.ldap.size = Le nombre d'entrées à traiter par le serveur LDAP dépasse sa capacité.
+error.spi.access.illegal.write = Impossible d'écrire les données.
+error.spi.access.illegal.write.ldap = Impossible d'écrire les données sur le serveur LDAP.
+error.spi.access.illegal.write.file = Impossible d'écrire les données dans le fichier.
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = Impossible d''écrire les données dans le fichier {0}.
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = Une erreur de connexion s''est produite avec l''URL {0}.
+error.spi.connection.open = Une erreur s''est produite lors de la connexion à {0}.
+error.spi.connection.close = Une erreur s''est produite lors de la fermeture de la connexion à {0}.
+error.spi.connection.interrupted = La connexion à {0} a été interrompue.
+# {1} is a number (size limit)
+error.spi.connection.size = La connexion à {0} ne peut pas définir la taille limite sur {1}.
+# {1} is the user name
+error.spi.connection.authentication = Une erreur s''est produite lors de la connexion de l'utilisateur {1} à {0}.
+# {1} is the user name
+error.spi.connection.authentication.notallowed = L'utilisateur {1} n''est pas autorisé à se connecter à {0}.
+
+# Entity
+error.spi.entity.filter.null = Le filtre utilisé pour la recherche est null.
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = Le filtre utilisé pour la recherche ({0}) n''est pas valide.
+# {0} is the id of the entity
+error.spi.entity.noexist = L''entité {0} n''existe pas.
+
+# Profile
+error.spi.profile.name.null = Le nom d'affichage du profil est null.
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = Le nom d''affichage du profil ({0}) n''est pas valide.
+# {0} is the id of the profile
+error.spi.profile.invalid.id = L''ID {0} du profil n''est pas valide.
+
+error.spi.profile.applicability.unknown = Des conditions d'applications de type inconnu ne sont pas valides.
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = La priorité ({0,number,integer}) existe déjà.
+error.spi.profile.priority.invalid = La priorité ({0,number,integer}) n'est pas valide.
+
+error.spi.profile.invalid = Le profil n'est pas valide.
+error.spi.profile.invalid.assigned = Le profil est assigné à des entités.
+error.spi.profile.invalid.empty = Le profil ne contient aucune stratégie.
+# {0} id of the profile
+error.spi.profile.invalid.noexist = Le profil ({0}) n''existe pas.
+error.spi.profile.null = Le profil est null.
+
+error.spi.profile.stream.null = Le flux est null.
+error.spi.profile.stream.empty = La source ne contient aucunes données valides.
+error.spi.profile.stream.error = Erreur de flux pour les données du profil.
+error.spi.profile.zip = Erreur de compression (zip) des données du profil.
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = La stratégie {0} n''existe pas.
+error.spi.policy.null = La stratégie est null.
+error.spi.policies.null = Le jeu de stratégies est null ou vide.
+error.spi.policy.mismatch = Les ID de stratégie ne correspondent pas.
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = L''élément {0} {1} est obligatoire.
+error.spi.policytree.element.mandatory.noremove = Impossible de supprimer l''élément obligatoire {0} {1}.
+error.spi.policytree.element.readonly = L''élément {0} {1} est en lecture seule.
+error.spi.policytree.element.copy = Impossible de copier l''élément {0} {1}.
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = Le type de données {0} n''est pas valide.
+
+error.spi.policytree.policynode.invalid = Le nœud de stratégie n'est pas valide.
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = Le nœud de stratégie {0} est incompatible avec la stratégie {1}.
+error.spi.policytree.policynode.name.invalid = Le nom de nœud de stratégie ({0}) n''est pas valide.
+
+error.spi.policytree.property.invalid = La propriété n'est pas valide.
+error.spi.policytree.property.value.invalid = La valeur de la propriété n'est pas valide.
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = La propriété {0} ne peut pas être définie sur nil.
+error.spi.policytree.property.name.invalid = Le nom de propriété ({0}) n''est pas valide.
+
+error.spi.policytree.xml = Une erreur d'analyse XML s'est produite.
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_ja.properties b/src/com/sun/apoc/spi/resources/SPIErrors_ja.properties
new file mode 100644
index 0000000..db0aa45
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_ja.properties
@@ -0,0 +1,134 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_ja.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2006/02/24 14:55:05 $ $Revision: 1.1 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = \u5185\u90e8\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = \u30d1\u30e9\u30e1\u30fc\u30bf {0} \u304c\u539f\u56e0\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = \u30d1\u30e9\u30e1\u30fc\u30bf {0} \u304c\u539f\u56e0\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u5024\u306f {1} \u306b\u542b\u307e\u308c\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002
+error.spi.environment.parameter.missing = \u30d1\u30e9\u30e1\u30fc\u30bf {0} \u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = \u30d1\u30e9\u30e1\u30fc\u30bf {0} \u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u5024\u306f {1} \u306b\u542b\u307e\u308c\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = \u30d1\u30e9\u30e1\u30fc\u30bf {0} ({1}) \u304c\u7121\u52b9\u3067\u3059\u3002
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = \u30d1\u30e9\u30e1\u30fc\u30bf {0} ({1}) \u304c\u7121\u52b9\u3067\u3059\u3002\u5024\u306f {2} \u306b\u542b\u307e\u308c\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = \u30d5\u30a1\u30a4\u30eb {0} \u306e\u69cb\u6210\u30c7\u30fc\u30bf\u306e\u8aad\u307f\u53d6\u308a\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = LDAP \u30b5\u30fc\u30d0\u30fc {0} \u306e\u69cb\u6210\u30c7\u30fc\u30bf\u306e\u8aad\u307f\u53d6\u308a\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.spi.environment.remote.ldap.invalid = LDAP \u30b5\u30fc\u30d0\u30fc {0} \u4e0a\u306e\u69cb\u6210\u30c7\u30fc\u30bf\u304c\u7121\u52b9\u3067\u3059\u3002
+error.spi.environment.remote.metaconf.invalid = LDAP \u30e1\u30bf\u69cb\u6210\u30c7\u30fc\u30bf\u304c\u7121\u52b9\u3067\u3059\u3002
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = \u30af\u30e9\u30b9 {0} \u306e\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc\u3067\u3059\u3002
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = \u9069\u7528\u6761\u4ef6 {0} \u306e\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u3092\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3 {1} \u306b\u5272\u308a\u5f53\u3066\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+
+# Illegal Access
+error.spi.access.illegal.read = \u30c7\u30fc\u30bf\u3092\u8aad\u307f\u53d6\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+error.spi.access.illegal.read.ldap = LDAP \u306e\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u53d6\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+error.spi.access.illegal.read.file = \u30d5\u30a1\u30a4\u30eb\u306e\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u53d6\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = \u30c7\u30fc\u30bf\u3092\u30d5\u30a1\u30a4\u30eb {0} \u306b\u8aad\u307f\u53d6\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+error.spi.access.illegal.read.ldap.size = LDAP \u30b5\u30fc\u30d0\u30fc\u4e0a\u3067\u51e6\u7406\u3059\u308b\u9805\u76ee\u6570\u304c\u30b5\u30fc\u30d0\u30fc\u306e\u5236\u9650\u3088\u308a\u3082\u5927\u304d\u304f\u306a\u3063\u3066\u3044\u307e\u3059\u3002
+error.spi.access.illegal.write = \u30c7\u30fc\u30bf\u3092\u66f8\u304d\u8fbc\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+error.spi.access.illegal.write.ldap = LDAP \u306e\u30c7\u30fc\u30bf\u3092\u66f8\u304d\u8fbc\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+error.spi.access.illegal.write.file = \u30d5\u30a1\u30a4\u30eb\u306e\u30c7\u30fc\u30bf\u3092\u66f8\u304d\u8fbc\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = \u30d5\u30a1\u30a4\u30eb {0} \u3092\u4f5c\u6210\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = URL {0} \u3067\u63a5\u7d9a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.spi.connection.open = {0} \u3068\u306e\u63a5\u7d9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.spi.connection.close = {0} \u3068\u306e\u63a5\u7d9a\u306e\u7d42\u4e86\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.spi.connection.interrupted = {0} \u3078\u306e\u63a5\u7d9a\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3057\u305f\u3002
+# {1} is a number (size limit)
+error.spi.connection.size = {0} \u3078\u306e\u63a5\u7d9a\u306b\u3088\u308a\u3001\u30b5\u30a4\u30ba\u5236\u9650\u3092 {1} \u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
+# {1} is the user name
+error.spi.connection.authentication = \u30e6\u30fc\u30b6\u30fc {1} \u3092 {0} \u306b\u63a5\u7d9a\u4e2d\u306b\u8a8d\u8a3c\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+# {1} is the user name
+error.spi.connection.authentication.notallowed = \u30e6\u30fc\u30b6\u30fc {1} \u306f {0} \u3078\u306e\u63a5\u7d9a\u304c\u8a31\u53ef\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+
+# Entity
+error.spi.entity.filter.null = \u30ea\u30b5\u30fc\u30c1\u306b\u4f7f\u7528\u3059\u308b\u30d5\u30a3\u30eb\u30bf\u304c\u30cc\u30eb\u3067\u3059\u3002
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = \u30ea\u30b5\u30fc\u30c1 ({0}) \u306b\u4f7f\u7528\u3059\u308b\u30d5\u30a3\u30eb\u30bf\u304c\u7121\u52b9\u3067\u3059\u3002
+# {0} is the id of the entity
+error.spi.entity.noexist = \u30a8\u30f3\u30c6\u30a3\u30c6\u30a3 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
+
+# Profile
+error.spi.profile.name.null = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u8868\u793a\u540d\u304c\u30cc\u30eb\u3067\u3059\u3002
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u8868\u793a\u540d ({0}) \u304c\u7121\u52b9\u3067\u3059\u3002
+# {0} is the id of the profile
+error.spi.profile.invalid.id = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb ID {0} \u304c\u7121\u52b9\u3067\u3059\u3002
+
+error.spi.profile.applicability.unknown = \u300cunknown\u300d\u306e\u7a2e\u985e\u306e\u9069\u7528\u6761\u4ef6\u304c\u7121\u52b9\u3067\u3059\u3002
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = \u512a\u5148\u5ea6 ({0,number,integer}) \u306f\u3059\u3067\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059\u3002
+error.spi.profile.priority.invalid = \u512a\u5148\u5ea6 ({0,number,integer}) \u304c\u7121\u52b9\u3067\u3059\u3002
+
+error.spi.profile.invalid = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u304c\u7121\u52b9\u3067\u3059\u3002
+error.spi.profile.invalid.assigned = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u306f\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u306b\u5272\u308a\u5f53\u3066\u6e08\u307f\u3067\u3059\u3002
+error.spi.profile.invalid.empty = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u306b\u30dd\u30ea\u30b7\u30fc\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+# {0} id of the profile
+error.spi.profile.invalid.noexist = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb ({0}) \u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
+error.spi.profile.null = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u304c\u30cc\u30eb\u3067\u3059\u3002
+
+error.spi.profile.stream.null = \u30b9\u30c8\u30ea\u30fc\u30e0\u304c\u30cc\u30eb\u3067\u3059\u3002
+error.spi.profile.stream.empty = \u30bd\u30fc\u30b9\u306b\u6709\u52b9\u306a\u30c7\u30fc\u30bf\u304c\u3042\u308a\u307e\u305b\u3093\u3002
+error.spi.profile.stream.error = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u30c7\u30fc\u30bf\u306e\u30b9\u30c8\u30ea\u30fc\u30e0\u306b\u30a8\u30e9\u30fc\u304c\u3042\u308a\u307e\u3059\u3002
+error.spi.profile.zip = \u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u30c7\u30fc\u30bf\u306e\u5727\u7e2e\u30a8\u30e9\u30fc\u3067\u3059\u3002
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = \u30dd\u30ea\u30b7\u30fc {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
+error.spi.policy.null = \u30dd\u30ea\u30b7\u30fc\u304c\u30cc\u30eb\u3067\u3059\u3002
+error.spi.policies.null = \u30dd\u30ea\u30b7\u30fc\u306e\u30bb\u30c3\u30c8\u304c\u30cc\u30eb\u307e\u305f\u306f\u7a7a\u3067\u3059\u3002
+error.spi.policy.mismatch = \u30dd\u30ea\u30b7\u30fc ID \u304c\u4e00\u81f4\u3057\u307e\u305b\u3093\u3002
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = {0} {1} \u306f\u5fc5\u9808\u3067\u3059\u3002
+error.spi.policytree.element.mandatory.noremove = {0} {1} \u306f\u5fc5\u9808\u3067\u3001\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3002
+error.spi.policytree.element.readonly = {0} {1} \u306f\u8aad\u307f\u53d6\u308a\u5c02\u7528\u3067\u3059\u3002
+error.spi.policytree.element.copy = {0} {1} \u306e\u30b3\u30d4\u30fc\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = DataType {0} \u304c\u7121\u52b9\u3067\u3059\u3002
+
+error.spi.policytree.policynode.invalid = PolicyNode \u304c\u7121\u52b9\u3067\u3059\u3002
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = PolicyNode {0} \u306f\u30dd\u30ea\u30b7\u30fc {1} \u3068\u4e92\u63db\u6027\u304c\u3042\u308a\u307e\u305b\u3093\u3002
+error.spi.policytree.policynode.name.invalid = PolicyNode \u540d ({0}) \u304c\u7121\u52b9\u3067\u3059\u3002
+
+error.spi.policytree.property.invalid = Property \u304c\u7121\u52b9\u3067\u3059\u3002
+error.spi.policytree.property.value.invalid = Property \u5024\u304c\u7121\u52b9\u3067\u3059\u3002
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = Property {0} \u306f\u30cc\u30eb\u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002
+error.spi.policytree.property.name.invalid = Property \u540d ({0}) \u304c\u7121\u52b9\u3067\u3059\u3002
+
+error.spi.policytree.xml = XML \u69cb\u6587\u89e3\u6790\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_ko.properties b/src/com/sun/apoc/spi/resources/SPIErrors_ko.properties
new file mode 100644
index 0000000..8ad7d6a
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_ko.properties
@@ -0,0 +1,134 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_ko.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2006/02/24 14:55:05 $ $Revision: 1.1 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = \ub0b4\ubd80 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = \ub9e4\uac1c \ubcc0\uc218 {0}\uc774(\uac00) \uc624\ub958\ub97c \uc77c\uc73c\ud0b5\ub2c8\ub2e4.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = \ub9e4\uac1c \ubcc0\uc218 {0}\uc774(\uac00) \uc624\ub958\ub97c \uc77c\uc73c\ud0a4\uba70 \uac12\uc744 {1}(\uc73c)\ub85c \uad6c\uc131\ud574\uc57c \ud569\ub2c8\ub2e4.
+error.spi.environment.parameter.missing = \ub9e4\uac1c \ubcc0\uc218 {0}\uc774(\uac00) \uc5c6\uc2b5\ub2c8\ub2e4.
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = \ub9e4\uac1c \ubcc0\uc218 {0}\uc774(\uac00) \uc5c6\uc73c\uba70 \uac12\uc744 {1}(\uc73c)\ub85c \uad6c\uc131\ud574\uc57c \ud569\ub2c8\ub2e4.
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = \ub9e4\uac1c \ubcc0\uc218 {0}({1})\uc774(\uac00) \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = \ub9e4\uac1c \ubcc0\uc218 {0}({1})\uc774(\uac00) \uc720\ud6a8\ud558\uc9c0 \uc54a\uc73c\uba70 \uac12\uc744 {2}(\uc73c)\ub85c \uad6c\uc131\ud574\uc57c \ud569\ub2c8\ub2e4.
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = {0} \ud30c\uc77c\uc758 \uad6c\uc131 \ub370\uc774\ud130\ub97c \uc77d\ub294 \uc911\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = LDAP \uc11c\ubc84 {0}\uc5d0\uc11c \uad6c\uc131 \ub370\uc774\ud130\ub97c \uc77d\ub294 \uc911\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+error.spi.environment.remote.ldap.invalid = LDAP \uc11c\ubc84 {0}\uc758 \uad6c\uc131 \ub370\uc774\ud130\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+error.spi.environment.remote.metaconf.invalid = LDAP \uba54\ud0c0 \uad6c\uc131 \ub370\uc774\ud130\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = \ud074\ub798\uc2a4 {0}\uc744(\ub97c) \ub85c\ub4dc\ud558\ub294 \uc911\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = \uc5d4\ud2f0\ud2f0 {1}\uc5d0 \uc801\uc6a9 \uac00\ub2a5\uc131 {0}\uc778 \ud504\ub85c\ud544\uc744 \uc9c0\uc815\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+
+# Illegal Access
+error.spi.access.illegal.read = \ub370\uc774\ud130\ub97c \uc77d\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.access.illegal.read.ldap = LDAP \ub370\uc774\ud130\ub97c \uc77d\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.access.illegal.read.file = \ud30c\uc77c \ub370\uc774\ud130\ub97c \uc77d\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = {0} \ud30c\uc77c\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc77d\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.access.illegal.read.ldap.size = LDAP \uc11c\ubc84\uc5d0\uc11c \ucc98\ub9ac\ud560 \uc5d4\ud2f0\ud2f0 \uc218\uac00 \uc11c\ubc84 \ud55c\ub3c4\ubcf4\ub2e4 \ud07d\ub2c8\ub2e4.
+error.spi.access.illegal.write = \ub370\uc774\ud130\ub97c \uc4f8 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.access.illegal.write.ldap = LDAP \ub370\uc774\ud130\ub97c \uc4f8 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.access.illegal.write.file = \ud30c\uc77c \ub370\uc774\ud130\ub97c \uc4f8 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = {0} \ud30c\uc77c\uc744 \ub9cc\ub4e4 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = URL {0}\uc5d0 \uc5f0\uacb0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+error.spi.connection.open = {0}\uc5d0 \uc5f0\uacb0\ud558\ub294 \uc911\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+error.spi.connection.close = {0} \uc5f0\uacb0\uc744 \uc885\ub8cc\ud558\ub294 \uc911\uc5d0 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+error.spi.connection.interrupted = {0} \uc5f0\uacb0\uc774 \uc911\ub2e8\ub418\uc5c8\uc2b5\ub2c8\ub2e4.
+# {1} is a number (size limit)
+error.spi.connection.size = {0} \uc5f0\uacb0\uc5d0\uc11c \ud06c\uae30 \uc81c\ud55c\uc744 {1}(\uc73c)\ub85c \uc124\uc815\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+# {1} is the user name
+error.spi.connection.authentication = \uc0ac\uc6a9\uc790 {1}\uc744(\ub97c) {0}\uc5d0 \uc5f0\uacb0\ud558\ub294 \uc911\uc5d0 \uc778\uc99d \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
+# {1} is the user name
+error.spi.connection.authentication.notallowed = \uc0ac\uc6a9\uc790 {1}\uc774(\uac00) {0}\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4.
+
+# Entity
+error.spi.entity.filter.null = \ub9ac\uc11c\uce58\uc5d0 \uc0ac\uc6a9\ub41c \ud544\ud130\uac00 null\uc785\ub2c8\ub2e4.
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = \ub9ac\uc11c\uce58({0})\uc5d0 \uc0ac\uc6a9\ub41c \ud544\ud130\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+# {0} is the id of the entity
+error.spi.entity.noexist = \uc5d4\ud2f0\ud2f0 {0}\uc774(\uac00) \uc5c6\uc2b5\ub2c8\ub2e4.
+
+# Profile
+error.spi.profile.name.null = \ud504\ub85c\ud544 \ud45c\uc2dc \uc774\ub984\uc774 null\uc785\ub2c8\ub2e4.
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = \ud504\ub85c\ud544 \ud45c\uc2dc \uc774\ub984({0})\uc774 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+# {0} is the id of the profile
+error.spi.profile.invalid.id = \ud504\ub85c\ud544 ID {0}\uc774(\uac00) \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+error.spi.profile.applicability.unknown = \uc54c \uc218 \uc5c6\ub294 \uc720\ud615\uc758 \uc801\uc6a9 \uac00\ub2a5\uc131\uc774 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = \uc6b0\uc120 \uc21c\uc704({0,\uc22b\uc790,\uc815\uc218})\uac00 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4.
+error.spi.profile.priority.invalid = \uc6b0\uc120 \uc21c\uc704({0,\uc22b\uc790,\uc815\uc218})\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+error.spi.profile.invalid = \ud504\ub85c\ud544\uc774 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+error.spi.profile.invalid.assigned = \uc5d4\ud2f0\ud2f0\uc5d0 \ud504\ub85c\ud544\uc774 \uc9c0\uc815\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+error.spi.profile.invalid.empty = \ud504\ub85c\ud544\uc5d0 \uc815\ucc45\uc774 \ub4e4\uc5b4 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+# {0} id of the profile
+error.spi.profile.invalid.noexist = \ud504\ub85c\ud544({0})\uc774 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.profile.null = \ud504\ub85c\ud544\uc774 null\uc785\ub2c8\ub2e4.
+
+error.spi.profile.stream.null = \uc2a4\ud2b8\ub9bc\uc774 null\uc785\ub2c8\ub2e4.
+error.spi.profile.stream.empty = \uc18c\uc2a4\uc5d0 \uc720\ud6a8\ud55c \ub370\uc774\ud130\uac00 \ub4e4\uc5b4 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+error.spi.profile.stream.error = \ud504\ub85c\ud544 \ub370\uc774\ud130 \uc2a4\ud2b8\ub9bc\uc5d0 \uc624\ub958\uac00 \uc788\uc2b5\ub2c8\ub2e4.
+error.spi.profile.zip = \ud504\ub85c\ud544 \ub370\uc774\ud130\uc5d0 \uc555\ucd95 \uc624\ub958\uac00 \uc788\uc2b5\ub2c8\ub2e4.
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = \uc815\ucc45 {0}\uc774(\uac00) \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.policy.null = \uc815\ucc45\uc774 null\uc785\ub2c8\ub2e4.
+error.spi.policies.null = \uc815\ucc45 \uc9d1\ud569\uc774 null\uc774\uac70\ub098 \ube44\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+error.spi.policy.mismatch = \uc815\ucc45 ID\uac00 \uc77c\uce58\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = {0} {1}\uc740(\ub294) \ud544\uc218 \ud56d\ubaa9\uc785\ub2c8\ub2e4.
+error.spi.policytree.element.mandatory.noremove = {0} {1}\uc740(\ub294) \ud544\uc218 \ud56d\ubaa9\uc774\ubbc0\ub85c \uc81c\uac70\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.policytree.element.readonly = {0} {1}\uc740(\ub294) \uc77d\uae30 \uc804\uc6a9\uc785\ub2c8\ub2e4.
+error.spi.policytree.element.copy = {0} {1}\uc758 \ubcf5\uc0ac\ubcf8\uc744 \ub9cc\ub4e4 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = \ub370\uc774\ud130 \ud615\uc2dd {0}\uc774(\uac00) \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+error.spi.policytree.policynode.invalid = \uc815\ucc45 \ub178\ub4dc\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = \uc815\ucc45 \ub178\ub4dc {0}\uc774(\uac00) \uc815\ucc45 {1}\uacfc(\uc640) \ud638\ud658\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+error.spi.policytree.policynode.name.invalid = \uc815\ucc45 \ub178\ub4dc \uc774\ub984({0})\uc774 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+error.spi.policytree.property.invalid = \ub4f1\ub85d \uc815\ubcf4\uac00 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+error.spi.policytree.property.value.invalid = \ub4f1\ub85d \uc815\ubcf4 \uac12\uc774 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = \ub4f1\ub85d \uc815\ubcf4 {0}\uc744(\ub97c) \ub2d0\ub85c \uc124\uc815\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+error.spi.policytree.property.name.invalid = \ub4f1\ub85d \uc815\ubcf4 \uc774\ub984({0})\uc774 \uc720\ud6a8\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+
+error.spi.policytree.xml = XML \uad6c\ubb38 \ubd84\uc11d \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_zh_CN.properties b/src/com/sun/apoc/spi/resources/SPIErrors_zh_CN.properties
new file mode 100644
index 0000000..40079d9
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_zh_CN.properties
@@ -0,0 +1,134 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_zh_CN.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2006/02/24 14:55:05 $ $Revision: 1.1 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = \u51fa\u73b0\u5185\u90e8\u9519\u8bef
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = \u53c2\u6570 {0} \u5f15\u53d1\u9519\u8bef\u3002
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = \u53c2\u6570 {0} \u5f15\u53d1\u9519\u8bef\uff0c\u8be5\u503c\u5fc5\u987b\u5305\u542b\u5728 {1} \u4e2d\u3002
+error.spi.environment.parameter.missing = \u7f3a\u5c11\u53c2\u6570 {0}\u3002
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = \u7f3a\u5c11\u53c2\u6570 {0}\uff0c\u8be5\u503c\u5fc5\u987b\u5305\u542b\u5728 {1} \u4e2d\u3002
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = \u53c2\u6570 {0} ({1}) \u65e0\u6548\u3002
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = \u53c2\u6570 {0} ({1}) \u65e0\u6548\uff0c\u8be5\u503c\u5fc5\u987b\u5305\u542b\u5728 {2} \u4e2d\u3002
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = \u8bfb\u53d6\u6587\u4ef6 {0} \u4e2d\u7684\u914d\u7f6e\u6570\u636e\u65f6\u51fa\u9519\u3002
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = \u8bfb\u53d6 LDAP \u670d\u52a1\u5668 {0} \u4e0a\u7684\u914d\u7f6e\u6570\u636e\u65f6\u51fa\u9519\u3002
+error.spi.environment.remote.ldap.invalid = LDAP \u670d\u52a1\u5668 {0} \u4e0a\u7684\u914d\u7f6e\u6570\u636e\u65e0\u6548\u3002
+error.spi.environment.remote.metaconf.invalid = LDAP \u5143\u914d\u7f6e\u6570\u636e\u65e0\u6548\u3002
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = \u52a0\u8f7d\u7c7b {0} \u65f6\u51fa\u9519\u3002
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = \u65e0\u6cd5\u5c06\u9002\u7528\u6027 {0} \u7684\u914d\u7f6e\u6587\u4ef6\u6307\u5b9a\u7ed9\u5b9e\u4f53 {1}\u3002
+
+# Illegal Access
+error.spi.access.illegal.read = \u65e0\u6cd5\u8bfb\u53d6\u6570\u636e\u3002
+error.spi.access.illegal.read.ldap = \u65e0\u6cd5\u8bfb\u53d6 LDAP \u6570\u636e\u3002
+error.spi.access.illegal.read.file = \u65e0\u6cd5\u8bfb\u53d6\u6587\u4ef6\u6570\u636e\u3002
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = \u65e0\u6cd5\u8bfb\u53d6\u6587\u4ef6 {0} \u4e2d\u7684\u6570\u636e\u3002
+error.spi.access.illegal.read.ldap.size = \u8981\u5728 LDAP \u670d\u52a1\u5668\u4e0a\u5904\u7406\u7684\u5b9e\u4f53\u6570\u8d85\u51fa\u670d\u52a1\u5668\u9650\u5236\u3002
+error.spi.access.illegal.write = \u65e0\u6cd5\u5199\u5165\u6570\u636e\u3002
+error.spi.access.illegal.write.ldap = \u65e0\u6cd5\u5199\u5165 LDAP \u6570\u636e\u3002
+error.spi.access.illegal.write.file = \u65e0\u6cd5\u5199\u5165\u6587\u4ef6\u6570\u636e\u3002
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = \u65e0\u6cd5\u521b\u5efa\u6587\u4ef6 {0}\u3002
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = URL {0} \u51fa\u73b0\u8fde\u63a5\u9519\u8bef\u3002
+error.spi.connection.open = \u8fde\u63a5\u5230 {0} \u65f6\u51fa\u9519\u3002
+error.spi.connection.close = \u5173\u95ed\u5230 {0} \u7684\u8fde\u63a5\u65f6\u51fa\u9519\u3002
+error.spi.connection.interrupted = \u5230 {0} \u7684\u8fde\u63a5\u5df2\u88ab\u4e2d\u65ad\u3002
+# {1} is a number (size limit)
+error.spi.connection.size = \u65e0\u6cd5\u5c06 {0} \u8fde\u63a5\u7684\u5927\u5c0f\u9650\u5236\u8bbe\u7f6e\u4e3a {1}\u3002
+# {1} is the user name
+error.spi.connection.authentication = \u5c06\u7528\u6237 {1} \u8fde\u63a5\u5230 {0} \u65f6\u51fa\u73b0\u9a8c\u8bc1\u9519\u8bef\u3002
+# {1} is the user name
+error.spi.connection.authentication.notallowed = \u4e0d\u5141\u8bb8\u7528\u6237 {1} \u8fde\u63a5\u5230 {0}\u3002
+
+# Entity
+error.spi.entity.filter.null = \u7528\u4e8e\u641c\u7d22\u7684\u8fc7\u6ee4\u5668\u4e3a Null\u3002
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = \u7528\u4e8e\u641c\u7d22 ({0}) \u7684\u8fc7\u6ee4\u5668\u65e0\u6548\u3002
+# {0} is the id of the entity
+error.spi.entity.noexist = \u5b9e\u4f53 {0} \u4e0d\u5b58\u5728\u3002
+
+# Profile
+error.spi.profile.name.null = \u914d\u7f6e\u6587\u4ef6\u663e\u793a\u540d\u79f0\u4e3a Null\u3002
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = \u914d\u7f6e\u6587\u4ef6\u663e\u793a\u540d\u79f0 ({0}) \u65e0\u6548\u3002
+# {0} is the id of the profile
+error.spi.profile.invalid.id = \u914d\u7f6e\u6587\u4ef6 ID \u65e0\u6548\u3002
+
+error.spi.profile.applicability.unknown = \u7c7b\u578b\u672a\u77e5\u7684\u9002\u7528\u6027\u65e0\u6548\u3002
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = \u4f18\u5148\u7ea7 ({0,\u6570\u5b57,\u6574\u6570}) \u5df2\u88ab\u4f7f\u7528\u3002
+error.spi.profile.priority.invalid = \u4f18\u5148\u7ea7 ({0,\u6570\u5b57,\u6574\u6570}) \u65e0\u6548\u3002
+
+error.spi.profile.invalid = \u914d\u7f6e\u6587\u4ef6\u65e0\u6548\u3002
+error.spi.profile.invalid.assigned = \u914d\u7f6e\u6587\u4ef6\u5df2\u6307\u5b9a\u7ed9\u5b9e\u4f53\u3002
+error.spi.profile.invalid.empty = \u914d\u7f6e\u6587\u4ef6\u672a\u5305\u542b\u4efb\u4f55\u7b56\u7565\u3002
+# {0} id of the profile
+error.spi.profile.invalid.noexist = \u914d\u7f6e\u6587\u4ef6 ({0}) \u4e0d\u5b58\u5728\u3002
+error.spi.profile.null = \u914d\u7f6e\u6587\u4ef6\u4e3a Null\u3002
+
+error.spi.profile.stream.null = \u6570\u636e\u6d41\u4e3a Null\u3002
+error.spi.profile.stream.empty = \u6570\u636e\u6e90\u672a\u5305\u542b\u4efb\u4f55\u6709\u6548\u6570\u636e\u3002
+error.spi.profile.stream.error = \u914d\u7f6e\u6587\u4ef6\u6570\u636e\u6d41\u51fa\u9519\u3002
+error.spi.profile.zip = \u914d\u7f6e\u6587\u4ef6\u6570\u636e\u51fa\u73b0\u538b\u7f29\u9519\u8bef\u3002
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = \u7b56\u7565 {0} \u4e0d\u5b58\u5728\u3002
+error.spi.policy.null = \u7b56\u7565\u4e3a Null\u3002
+error.spi.policies.null = \u7b56\u7565\u96c6\u4e3a Null \u6216\u4e3a\u7a7a\u3002
+error.spi.policy.mismatch = \u7b56\u7565 ID \u4e0d\u5339\u914d\u3002
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = {0} {1} \u662f\u5fc5\u9700\u7684\u3002
+error.spi.policytree.element.mandatory.noremove = {0} {1} \u662f\u5fc5\u9700\u7684\uff0c\u4e0d\u80fd\u5c06\u5176\u5220\u9664\u3002
+error.spi.policytree.element.readonly = {0} {1} \u662f\u53ea\u8bfb\u7684\u3002
+error.spi.policytree.element.copy = \u65e0\u6cd5\u521b\u5efa {0} {1} \u7684\u526f\u672c\u3002
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = \u6570\u636e\u7c7b\u578b {0} \u65e0\u6548\u3002
+
+error.spi.policytree.policynode.invalid = \u7b56\u7565\u8282\u70b9\u65e0\u6548\u3002
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = \u7b56\u7565\u8282\u70b9 {0} \u4e0e\u7b56\u7565 {1} \u4e0d\u517c\u5bb9\u3002
+error.spi.policytree.policynode.name.invalid = \u7b56\u7565\u8282\u70b9\u540d\u79f0 ({0}) \u65e0\u6548\u3002
+
+error.spi.policytree.property.invalid = \u5c5e\u6027\u65e0\u6548\u3002
+error.spi.policytree.property.value.invalid = \u5c5e\u6027\u503c\u65e0\u6548\u3002
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = \u65e0\u6cd5\u5c06\u5c5e\u6027 {0} \u8bbe\u7f6e\u4e3a\u96f6\u3002
+error.spi.policytree.property.name.invalid = \u5c5e\u6027\u540d\u79f0 ({0}) \u65e0\u6548\u3002
+
+error.spi.policytree.xml = \u51fa\u73b0 XML \u89e3\u6790\u9519\u8bef\u3002
diff --git a/src/com/sun/apoc/spi/resources/SPIErrors_zh_TW.properties b/src/com/sun/apoc/spi/resources/SPIErrors_zh_TW.properties
new file mode 100644
index 0000000..950f280
--- /dev/null
+++ b/src/com/sun/apoc/spi/resources/SPIErrors_zh_TW.properties
@@ -0,0 +1,134 @@
+#
+#*******************************************************************************
+#* $RCSfile: SPIErrors_zh_TW.properties,v $
+#*
+#* Description: Default resource bundle for SPI errors
+#*
+#* Last change: $Date: 2006/02/24 14:55:05 $ $Revision: 1.1 $
+#*
+#* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use of this
+#* product is subject to license terms.
+#*
+#*******************************************************************************
+#
+
+error.spi.default = \u767c\u751f\u5167\u90e8\u932f\u8aa4
+
+# Environment
+# in all of this section, {0} is a parameter name
+error.spi.environment.parameter = \u53c3\u6578 {0} \u5c0e\u81f4\u932f\u8aa4\u3002
+# {1} is an intervall/range of values
+error.spi.environment.parameter.range = \u53c3\u6578 {0} \u5c0e\u81f4\u932f\u8aa4\uff0c\u8a72\u503c\u5fc5\u9808\u7d44\u5408\u65bc {1} \u5167\u3002
+error.spi.environment.parameter.missing = \u7f3a\u5c11\u53c3\u6578 {0}\u3002
+# {1} is an intervall/range of values
+error.spi.environment.parameter.missing.range = \u7f3a\u5c11\u53c3\u6578 {0}\uff0c\u8a72\u503c\u5fc5\u9808\u7d44\u5408\u65bc {1} \u5167\u3002
+# {1} is a value for the parameter
+error.spi.environment.parameter.invalid = \u53c3\u6578 {0} ({1}) \u7121\u6548\u3002
+# {1} is a value for the parameter and {2} is an intervall/range of values
+error.spi.environment.parameter.invalid.range = \u53c3\u6578 {0} ({1}) \u7121\u6548\uff0c\u8a72\u503c\u5fc5\u9808\u7d44\u5408\u65bc {2} \u5167\u3002
+
+# Remote Environment
+# {0} is a file name
+error.spi.environment.remote.file = \u8b80\u53d6\u6a94\u6848 {0} \u4e2d\u7684\u914d\u7f6e\u8cc7\u6599\u6642\uff0c\u767c\u751f\u932f\u8aa4\u3002
+# {0} is the URL of the server
+error.spi.environment.remote.ldap = \u8b80\u53d6 LDAP \u4f3a\u670d\u5668 {0} \u4e0a\u7684\u914d\u7f6e\u8cc7\u6599\u6642\uff0c\u767c\u751f\u932f\u8aa4\u3002
+error.spi.environment.remote.ldap.invalid = LDAP \u4f3a\u670d\u5668 {0} \u4e0a\u7684\u914d\u7f6e\u8cc7\u6599\u7121\u6548\u3002
+error.spi.environment.remote.metaconf.invalid = LDAP \u8907\u5408\u914d\u7f6e\u8cc7\u6599\u7121\u6548\u3002
+
+# Provider Loading
+# {0} is a full path.name of a class
+error.spi.provider.loading = \u8f09\u5165\u985e\u5225 {0} \u6642\u767c\u751f\u932f\u8aa4\u3002
+
+# Incompatible Assignment
+# {0} is the value of the Applicatbility
+# {1} is the display name of the entity
+error.spi.assignment.illegal = \u9069\u7528\u6027 {0} \u7684\u8a2d\u5b9a\u6a94\u4e0d\u80fd\u6307\u5b9a\u81f3\u5be6\u9ad4 {1}\u3002
+
+# Illegal Access
+error.spi.access.illegal.read = \u7121\u6cd5\u8b80\u53d6\u8cc7\u6599\u3002
+error.spi.access.illegal.read.ldap = \u7121\u6cd5\u8b80\u53d6 LDAP \u8cc7\u6599\u3002
+error.spi.access.illegal.read.file = \u7121\u6cd5\u8b80\u53d6\u6a94\u6848\u8cc7\u6599\u3002
+# {0} is the name of the file
+error.spi.access.illegal.read.file.name = \u7121\u6cd5\u8b80\u53d6\u6a94\u6848 {0} \u4e2d\u7684\u8cc7\u6599\u3002
+error.spi.access.illegal.read.ldap.size = \u5c07\u65bc LDAP \u4f3a\u670d\u5668\u4e0a\u8655\u7406\u7684\u9805\u76ee\u6578\u5927\u65bc\u4f3a\u670d\u5668\u9650\u5236\u3002
+error.spi.access.illegal.write = \u7121\u6cd5\u5beb\u5165\u8cc7\u6599\u3002
+error.spi.access.illegal.write.ldap = \u7121\u6cd5\u5beb\u5165 LDAP \u8cc7\u6599\u3002
+error.spi.access.illegal.write.file = \u7121\u6cd5\u5beb\u5165\u6a94\u6848\u8cc7\u6599\u3002
+# {0} is the name of the file
+error.spi.access.illegal.write.file.create = \u7121\u6cd5\u5efa\u7acb\u6a94\u6848 {0}\u3002
+
+# Connection
+# in all of this section, {0} is the URL for the connection
+error.spi.connection = URL {0} \u767c\u751f\u9023\u7dda\u932f\u8aa4\u3002
+error.spi.connection.open = \u9023\u7dda\u81f3 {0} \u6642\u767c\u751f\u932f\u8aa4\u3002
+error.spi.connection.close = \u95dc\u9589\u8207 {0} \u7684\u9023\u7dda\u6642\u751f\u932f\u8aa4\u3002
+error.spi.connection.interrupted = \u5df2\u4e2d\u65b7\u8207 {0} \u7684\u9023\u7dda\u3002
+# {1} is a number (size limit)
+error.spi.connection.size = \u7121\u6cd5\u5c07\u8207 {0} \u7684\u9023\u7dda\u5927\u5c0f\u9650\u5236\u8a2d\u5b9a\u70ba {1}\u3002
+# {1} is the user name
+error.spi.connection.authentication = \u5c07\u4f7f\u7528\u8005 {1} \u9023\u7dda\u81f3 {0} \u6642\uff0c\u767c\u751f\u8a8d\u8b49\u932f\u8aa4\u3002
+# {1} is the user name
+error.spi.connection.authentication.notallowed = \u4e0d\u5141\u8a31\u4f7f\u7528\u8005 {1} \u9023\u7dda\u81f3 {0}\u3002
+
+# Entity
+error.spi.entity.filter.null = \u641c\u5c0b\u6240\u7528\u7684\u7be9\u9078\u5668\u70ba\u7a7a\u503c\u3002
+# {0} is the string used as filter
+error.spi.entity.filter.invalid = \u641c\u5c0b ({0}) \u6240\u7528\u7684\u7be9\u9078\u5668\u7121\u6548\u3002
+# {0} is the id of the entity
+error.spi.entity.noexist = \u5be6\u9ad4 {0} \u4e0d\u5b58\u5728\u3002
+
+# Profile
+error.spi.profile.name.null = \u8a2d\u5b9a\u6a94\u986f\u793a\u540d\u7a31\u70ba\u7a7a\u503c\u3002
+# {0} is the display name of the profile
+error.spi.profile.name.invalid = \u8a2d\u5b9a\u6a94\u986f\u793a\u540d\u7a31 ({0}) \u7121\u6548\u3002
+# {0} is the id of the profile
+error.spi.profile.invalid.id = \u8a2d\u5b9a\u6a94 ID {0} \u7121\u6548\u3002
+
+error.spi.profile.applicability.unknown = \u985e\u578b\u4e0d\u660e\u7684\u9069\u7528\u6027\u7121\u6548\u3002
+
+# {0,number,integer} is the value (int) of the priority
+error.spi.profile.priority.used = \u512a\u5148\u6b0a ({0,\u6578\u5b57,\u6574\u6578}) \u5df2\u5728\u4f7f\u7528\u3002
+error.spi.profile.priority.invalid = \u512a\u5148\u6b0a ({0,\u6578\u5b57,\u6574\u6578}) \u7121\u6548\u3002
+
+error.spi.profile.invalid = \u8a2d\u5b9a\u6a94\u7121\u6548\u3002
+error.spi.profile.invalid.assigned = \u8a2d\u5b9a\u6a94\u5df2\u6307\u5b9a\u7d66\u5be6\u9ad4\u3002
+error.spi.profile.invalid.empty = \u8a2d\u5b9a\u6a94\u4e0d\u5305\u542b\u4efb\u4f55\u7b56\u7565\u3002
+# {0} id of the profile
+error.spi.profile.invalid.noexist = \u8a2d\u5b9a\u6a94 ({0}) \u4e0d\u5b58\u5728\u3002
+error.spi.profile.null = \u8a2d\u5b9a\u6a94\u70ba\u7a7a\u503c\u3002
+
+error.spi.profile.stream.null = \u4e32\u6d41\u70ba\u7a7a\u503c\u3002
+error.spi.profile.stream.empty = \u4f86\u6e90\u4e0d\u5305\u542b\u4efb\u4f55\u6709\u6548\u8cc7\u6599\u3002
+error.spi.profile.stream.error = \u8a2d\u5b9a\u6a94\u8cc7\u6599\u7684\u4e32\u6d41\u4e0a\u767c\u751f\u932f\u8aa4\u3002
+error.spi.profile.zip = \u8a2d\u5b9a\u6a94\u8cc7\u6599\u4e0a\u767c\u751f\u58d3\u7e2e\u932f\u8aa4\u3002
+
+# Policy
+# {0} is the id of the policy
+error.spi.policy.noexist = \u7b56\u7565 {0} \u4e0d\u5b58\u5728\u3002
+error.spi.policy.null = \u7b56\u7565\u70ba\u7a7a\u503c\u3002
+error.spi.policies.null = \u7b56\u7565\u96c6\u70ba\u7a7a\u503c\u6216\u662f\u7a7a\u7684\u3002
+error.spi.policy.mismatch = \u7b56\u7565 ID \u4e0d\u76f8\u7b26\u3002
+
+# PolicyTree
+# {0} can have PolicyNode or Property for values
+# {1} is the name of the PolicyNode/Property
+error.spi.policytree.element.mandatory = {0} {1} \u662f\u5fc5\u8981\u9805\u76ee\u3002
+error.spi.policytree.element.mandatory.noremove = {0} {1} \u662f\u5fc5\u8981\u9805\u76ee\uff0c\u7121\u6cd5\u5c07\u5176\u79fb\u9664\u3002
+error.spi.policytree.element.readonly = {0} {1} \u662f\u552f\u8b80\u9805\u76ee\u3002
+error.spi.policytree.element.copy = \u7121\u6cd5\u5efa\u7acb {0} {1} \u7684\u8907\u672c\u3002
+
+# {0} is a String representing the value of the DataType
+error.spi.policytree.datatype.invalid = \u8cc7\u6599\u985e\u578b {0} \u7121\u6548\u3002
+
+error.spi.policytree.policynode.invalid = \u7b56\u7565\u7bc0\u9ede\u7121\u6548\u3002
+# {0} is the name of the PolicyNode
+error.spi.policytree.policynode.incompatible = \u7b56\u7565\u7bc0\u9ede {0} \u8207\u7b56\u7565 {1} \u4e0d\u76f8\u5bb9\u3002
+error.spi.policytree.policynode.name.invalid = \u7b56\u7565\u7bc0\u9ede\u540d\u7a31 ({0}) \u7121\u6548\u3002
+
+error.spi.policytree.property.invalid = \u7279\u6027\u7121\u6548\u3002
+error.spi.policytree.property.value.invalid = \u7279\u6027\u503c\u7121\u6548\u3002
+# {0} is the name of the Property
+error.spi.policytree.property.nonil = \u7279\u6027 {0} \u4e0d\u80fd\u8a2d\u5b9a\u70ba\u96f6\u3002
+error.spi.policytree.property.name.invalid = \u7279\u6027\u540d\u7a31 ({0}) \u7121\u6548\u3002
+
+error.spi.policytree.xml = \u767c\u751f XML \u5256\u6790\u932f\u8aa4\u3002
diff --git a/src/com/sun/apoc/spi/util/BooleanReturnValue.java b/src/com/sun/apoc/spi/util/BooleanReturnValue.java
new file mode 100644
index 0000000..11232ef
--- /dev/null
+++ b/src/com/sun/apoc/spi/util/BooleanReturnValue.java
@@ -0,0 +1,53 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.util;
+
+/**
+ * Class for handling boolean return values.
+ *
+ */
+public class BooleanReturnValue {
+ private boolean mReturnValue;
+ public BooleanReturnValue(boolean aValue) {
+ mReturnValue = aValue;
+ }
+ public void setReturnValue(boolean aValue) {
+ mReturnValue = aValue;
+ }
+ public boolean getReturnValue() {
+ return mReturnValue;
+ }
+}
diff --git a/src/com/sun/apoc/spi/util/ImporterExporter.java b/src/com/sun/apoc/spi/util/ImporterExporter.java
new file mode 100644
index 0000000..4c68ed2
--- /dev/null
+++ b/src/com/sun/apoc/spi/util/ImporterExporter.java
@@ -0,0 +1,78 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.util;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+
+/**
+ * Common interface handling the import/export of a profile.
+ * Each implementation must define the actual format of the
+ * exported data.
+ */
+public interface ImporterExporter {
+
+ /**
+ * Exports the contents of a profile to a stream.
+ *
+ * @param aProfile profile identifier
+ * @param aOutput stream for exported data
+ * @throws SPIException if an error occurs.
+ */
+ public void exportProfile(Profile aProfile, OutputStream aOutput)
+ throws SPIException;
+
+ /**
+ * Imports the contents of a stream to a profile.
+ * If a profile with this name already exists then
+ * it is overwritten.
+ *
+ * @param aRepository profile repository
+ * @param aDisplayName profile display name
+ * @param aApplicability scope
+ * @param aInput stream containing data to import
+ *
+ * @throws SPIException if an error occurs.
+ */
+ public void importProfile(ProfileRepository aRepository,
+ String aDisplayName, Applicability aApplicability, InputStream aInput)
+ throws SPIException;
+}
diff --git a/src/com/sun/apoc/spi/util/MetaConfiguration.java b/src/com/sun/apoc/spi/util/MetaConfiguration.java
new file mode 100644
index 0000000..585bef0
--- /dev/null
+++ b/src/com/sun/apoc/spi/util/MetaConfiguration.java
@@ -0,0 +1,258 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.util;
+
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.environment.RemoteEnvironmentException;
+
+/**
+ * Meta-configuration source.
+ *
+ */
+
+public class MetaConfiguration {
+ /** value of separator for list items in the metaconfiguration */
+ public static final String SEPARATOR = ",";
+ /** Table for storing metaconfiguration data*/
+ private Hashtable mTable;
+
+ /**
+ * Constructor initialises the table.
+ *
+ * @param aTable the table containing the properties.
+ * @throws <code>SPIException</code> if table
+ * does not exist or is empty
+ */
+ public MetaConfiguration(Hashtable aTable)
+ throws SPIException {
+ if (aTable == null || aTable.isEmpty()) {
+ throw new RemoteEnvironmentException (
+ RemoteEnvironmentException.INVALID_META_CONF_KEY,
+ null);
+ }
+ mTable = aTable;
+ }
+
+ /**
+ * Get the Hashtable containing the metaconfiguration properties
+ *
+ * @return the hashtable containing the properties
+ */
+ public Hashtable getTable() {
+ return mTable;
+ }
+
+ /**
+ * Searches the table for the <code>String</code> value
+ * for the property with the specified aKey. Returns the default
+ * value provided if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @param aDefaultValue a default value to be used if there
+ * is no value for the required property
+ * @return <code>String</code> value of property
+ */
+ public String getString(String aKey, String aDefaultValue) {
+ String retCode = getString(aKey);
+ if (retCode == null && aDefaultValue != null) {
+ retCode = aDefaultValue.trim();
+ }
+ return retCode;
+ }
+
+ /**
+ * Searches the table for the <code>String</code> value
+ * for the property with the specified aKey. Returns
+ * <code>null</code> if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @return <code>String</code> value of property,
+ * or <code>null</code> if property not
+ * found
+ */
+ public String getString(String aKey) {
+ String retCode = (String)mTable.get(aKey) ;
+ if (retCode != null) {
+ retCode = retCode.trim();
+ }
+ return retCode;
+ }
+
+ /**
+ * Searches for the <code>String</code> value for the
+ * property with the specified aKey. Converts this String
+ * to an array of Strings (using mSeparator as the delimeter), and
+ * returns this array.
+ * Returns <code>null</code> if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @return <code>String</code> value of property,
+ * or <code>null</code> if property not
+ * found
+ */
+ public String[] getStrings(String aKey) {
+ return getStrings(aKey, SEPARATOR) ;
+ }
+
+ /**
+ * Searches for the <code>String</code> value for the
+ * property with the specified aKey. Converts this String
+ * to an array of Strings (using aSeparator as the delimeter), and
+ * returns this array.
+ * Returns <code>null</code> if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @param aSeparator separator to use to split the strings
+ * @return <code>String</code> value of property,
+ * or <code>null</code> if property not
+ * found
+ */
+ public String[] getStrings(String aKey, String aSeparator) {
+ String value = null;
+ StringTokenizer st = null;
+ String []stringArray = null;
+ value = getString(aKey);
+ if (value == null) { return stringArray ;}
+ st = new StringTokenizer(value, aSeparator);
+ int total = st.countTokens();
+ if (total > 0) {
+ stringArray = new String[total];
+ for (int i = 0; i < total; i++) {
+ stringArray[i] = st.nextToken().trim();
+ }
+ }
+ return stringArray;
+ }
+
+ /**
+ * Searches for the <code>boolean</code> value for the
+ * property with the specified aKey. Returns the default
+ * value provided if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @param aDefaultValue a default value to be used if there
+ * is no value for the required property
+ * @return <code>boolean</code> value of property
+ */
+ public boolean getBoolean(String aKey, boolean aDefaultValue) {
+ String value = getString(aKey) ;
+ if (value == null) { return aDefaultValue ; }
+ return Boolean.valueOf(value).booleanValue() ;
+ }
+
+ /**
+ * Searches for the <code>boolean</code> value for the
+ * property with the specified aKey. Returns the default
+ * value provided if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @param aDefaultValue a default value to be used if there
+ * is no value for the required property
+ * @return <code>boolean</code> value of property
+ */
+ public boolean getBoolean(String aKey, String aDefaultValue) {
+ String value = getString(aKey, aDefaultValue);
+ return Boolean.valueOf(value).booleanValue() ;
+ }
+
+ /**
+ * Searches for the <code>boolean</code> value for
+ * the property with the specified aKey. Returns
+ * <code>false</code> if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @return <code>boolean</code> value of property,
+ * or false if unsuccessful
+ */
+ public boolean getBoolean(String aKey) {
+ return getBoolean(aKey, false) ;
+ }
+
+ /**
+ * Searches for the <code>int</code> value for the
+ * property with the specified aKey. Returns the default
+ * value provided if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @param aDefault a default value to be used if there
+ * is no value for the required property
+ * @return <code>int</code> value of property
+ * @throws <code>NumberFormatException</code> if cannot
+ * convert <code>String</code> to <code>int</code>
+ */
+ public int getInt(String aKey,
+ int aDefault) throws NumberFormatException {
+ String value = getString(aKey) ;
+ if (value == null) { return aDefault ; }
+ return Integer.parseInt(value) ;
+ }
+
+ /**
+ * Searches for the <code>int</code> value for the
+ * property with the specified aKey. Returns the default
+ * value provided if the property cannot be found.
+ *
+ * @param aKey aKey for the required property
+ * @param aDefaultValue a default value to be used if there
+ * is no value for the required property
+ * @return <code>int</code> value of property
+ * @throws <code>NumberFormatException</code> if cannot
+ * convert <code>String</code> to <code>int</code>
+ */
+ public int getInt(String aKey,
+ String aDefaultValue) throws NumberFormatException{
+ String value = getString(aKey, aDefaultValue);
+ return Integer.parseInt(value);
+ }
+
+ /**
+ * Searches for the <code>int</code> value for the
+ * property with the specified aKey. Returns -1 if property
+ * not found.
+ *
+ * @param aKey aKey for the required property
+ * @return <code>int</code> value of property
+ * @throws <code>NumberFormatException</code> if cannot
+ * convert <code>String</code> to <code>int</code>
+ */
+ public int getInt(String aKey) throws NumberFormatException {
+ return getInt(aKey, -1) ;
+ }
+}
+
diff --git a/src/com/sun/apoc/spi/util/StringEnum.java b/src/com/sun/apoc/spi/util/StringEnum.java
new file mode 100644
index 0000000..00fe710
--- /dev/null
+++ b/src/com/sun/apoc/spi/util/StringEnum.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.util;
+
+/**
+ * Class <code>StringEnum</code> is an abstract base class for
+ * the String version of a C/C++ enum.
+ * <p>
+ * StringEnum is immutable, which means that once it has been constructed,
+ * it cannot be modified. The only instance member variable is <code>value</code>
+ * which is private; subclasses can read it's value only through getIntValue().
+ * See also StringRangeEnum, a subclass that enforces a contiguous range of
+ * integer values.
+ *
+ */
+
+abstract public class StringEnum {
+
+ /**
+ * we store the value of a StringEnum as an int because it is
+ * compact, easy to check and easy to convert to a String
+ * using enumIntToString(value)
+ */
+ private int value;
+
+ protected StringEnum(int n) {
+ value = n;
+ }
+
+ /**
+ * Obtain value for this StringEnum in the form of an int.
+ */
+ public int getIntValue() {
+ return value;
+ }
+
+ public String toString() {
+ return getStringValue();
+ }
+
+ /* ### { abstract methods to be implemented in concrete classes */
+
+ abstract public String getStringValue();
+
+ /* ### } */
+}
diff --git a/src/com/sun/apoc/spi/util/StringRangeEnum.java b/src/com/sun/apoc/spi/util/StringRangeEnum.java
new file mode 100644
index 0000000..5071f77
--- /dev/null
+++ b/src/com/sun/apoc/spi/util/StringRangeEnum.java
@@ -0,0 +1,86 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.spi.util;
+
+/**
+ * Class <code>StringRangeEnum</code> is an abstract base class for
+ * the String version of a C/C++ enum where the String values map
+ * to integer values starting at 0 and monotonically increasing
+ * to N-1, where N is the number of String values in this Enum.
+ *
+ * StringEnum classes are immutable; subclasses are expected to implement
+ * one or more static factory methods: enum(int) and enum(String)
+ *
+ */
+
+abstract public class StringRangeEnum extends StringEnum {
+
+ public static final int UNKNOWN_ENUM = -1;
+
+ protected StringRangeEnum (int n) {
+ super(n);
+ }
+
+ /* getEnums() and getEnumStrings() should be implemented by any derived
+ * class, to list String and StringEnum values for this StringEnum in
+ * the same order.
+ */
+ abstract protected String[] getEnumStrings();
+
+ public int getMaxIntValue () {
+ return getEnumStrings().length-1;
+ }
+
+ public String enumString(int n) {
+ String strings[] = getEnumStrings();
+
+ if (n >=0 && n < strings.length)
+ return strings[n];
+
+ return null;
+ }
+
+ /**
+ * Obtain value for this StringEnum in the form of a String.
+ */
+ public String getStringValue() {
+ String strings[] = getEnumStrings();
+ int n = getIntValue();
+ if (n >= 0)
+ return strings[n];
+
+ return null;
+ }
+}
diff --git a/src/com/sun/apoc/spi/util/ZipImporterExporter.java b/src/com/sun/apoc/spi/util/ZipImporterExporter.java
new file mode 100644
index 0000000..64c8b54
--- /dev/null
+++ b/src/com/sun/apoc/spi/util/ZipImporterExporter.java
@@ -0,0 +1,200 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+
+package com.sun.apoc.spi.util;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.zip.ZipException;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import com.sun.apoc.spi.SPIException;
+import com.sun.apoc.spi.entities.Entity;
+import com.sun.apoc.spi.policies.Policy;
+import com.sun.apoc.spi.profiles.Applicability;
+import com.sun.apoc.spi.profiles.Profile;
+import com.sun.apoc.spi.profiles.ProfileRepository;
+import com.sun.apoc.spi.profiles.ProfileStreamException;
+import com.sun.apoc.spi.profiles.ProfileZipException;
+import com.sun.apoc.spi.profiles.ZipProfileReadWrite;
+import java.util.ArrayList;
+/**
+ * Implementation of the importer/exporter of profiles in ZIP file format.
+ */
+public class ZipImporterExporter implements ImporterExporter {
+
+ /**
+ * Exports the contents of a profile to a stream.
+ *
+ * @param aProfile profile identifier
+ * @param aOutput stream for exported data
+ * @throws SPIException if an error occurs.
+ */
+ public void exportProfile(Profile aProfile, OutputStream aOutput)
+ throws SPIException {
+ ZipOutputStream output = new ZipOutputStream(aOutput);
+ try {
+ ZipProfileReadWrite.writeMetaData(aProfile, output);
+ ZipProfileReadWrite.writePolicies(aProfile, output);
+ output.close();
+
+ } catch (ZipException ze) {
+ try {
+ output.close();
+ } catch (Exception ignored) {}
+ throw new ProfileZipException(ze);
+
+ } catch (IOException ioe) {
+ try {
+ output.close();
+ } catch (Exception ignored) {}
+ throw new ProfileStreamException(
+ ProfileStreamException.ERROR_STREAM_KEY, ioe);
+ }
+ }
+
+
+
+ /**
+ * Imports the contents of a stream to a profile.
+ * If a profile with this name already exists then
+ * it is overwritten.
+ *
+ * @param aRepository profile repository
+ * @param aDisplayName profile display name
+ * @param aApplicability scope
+ * @param aInput stream containing data to import
+ *
+ * @throws SPIException if an error occurs.
+ */
+ public void importProfile(ProfileRepository aRepository,
+ String aDisplayName, Applicability aApplicability,
+ InputStream aInput) throws SPIException {
+ ZipInputStream input = new ZipInputStream(aInput);
+ try {
+ // first try to read the meta configuration data
+ Properties metaData = ZipProfileReadWrite.readMetaData(input);
+ Iterator it = null;
+ if (metaData != null) {
+ Applicability zippedApplicability = Applicability.getApplicability(metaData.getProperty(ZipProfileReadWrite.APPLICABILITY));
+ if (!(aApplicability.equals(zippedApplicability))) {
+ Object[] obj = {zippedApplicability.getStringValue(), aApplicability.getStringValue()};
+ throw new SPIException("error.spi.profile.import", obj);
+ }
+ // then try to load the policy data
+ it = ZipProfileReadWrite.readPolicies(input);
+ } else {
+ aApplicability = Applicability.USER;
+ // if meta data entry does not exist, we assume the old
+ // profile/policy format
+ it = ZipProfileReadWrite.readOldPoliciesFormat(input);
+ // if 'it' contains no data that means it is either an old
+ // format source but with no policies in it or that the source
+ // doesn't have the required format (new or old)
+ // in both cases, raise an exception.
+ if (!it.hasNext()) {
+ input.close();
+ throw new ProfileStreamException(ProfileStreamException.EMPTY_STREAM_KEY);
+ }
+ }
+ input.close();
+
+ // check if a profile with the same name and applicability already exists - in that
+ // case we want to overwrite it
+ Iterator profiles = aRepository.getProfiles(aApplicability);
+ ArrayList assignedEntities = new ArrayList();
+ while (profiles.hasNext()) {
+ Profile profile = (Profile)profiles.next();
+ if (profile != null) {
+ if (profile.getDisplayName().equals(aDisplayName)) {
+ Applicability use = profile.getApplicability();
+ if (use.equals(aApplicability)) {
+ Iterator entityIt = profile.getAssignedEntities();
+ while(entityIt.hasNext()) {
+ Entity entity = (Entity)entityIt.next();
+ assignedEntities.add(entity);
+ entity.unassignProfile(profile);
+ }
+ aRepository.destroyProfile(profile);
+ }
+ }
+ }
+ }
+
+ // create a new profile with specified name and applicability
+ Profile profile = aRepository.createProfile(aDisplayName, aApplicability);
+
+ // store the policies
+ while(it.hasNext()) {
+ profile.storePolicy((Policy) it.next());
+ }
+
+ // update the meta data
+ if (metaData != null) {
+ profile.setComment(metaData.getProperty(ZipProfileReadWrite.COMMENT));
+ }
+
+ if (assignedEntities.size() != 0) {
+ Iterator entityIt = assignedEntities.iterator();
+ if (entityIt != null) {
+ while (entityIt.hasNext()) {
+ Entity entityToAssign = (Entity)entityIt.next();
+ entityToAssign.assignProfile(profile);
+ }
+ }
+ }
+
+ } catch (ZipException ze) {
+ try {
+ input.close();
+ } catch (Exception ignored) {}
+ throw new ProfileZipException(ze);
+
+ } catch (IOException ioe) {
+ try {
+ input.close();
+ } catch (Exception ignored) {}
+ throw new ProfileStreamException(
+ ProfileStreamException.ERROR_STREAM_KEY, ioe);
+ }
+ }
+
+}
+