1 package org
.argeo
.util
.naming
;
3 import static org
.argeo
.util
.naming
.LdapAttrs
.DN
;
4 import static org
.argeo
.util
.naming
.LdapAttrs
.member
;
5 import static org
.argeo
.util
.naming
.LdapAttrs
.objectClass
;
6 import static org
.argeo
.util
.naming
.LdapAttrs
.uniqueMember
;
8 import java
.io
.IOException
;
9 import java
.io
.OutputStream
;
10 import java
.io
.OutputStreamWriter
;
11 import java
.io
.Writer
;
12 import java
.nio
.charset
.Charset
;
13 import java
.nio
.charset
.StandardCharsets
;
14 import java
.util
.Base64
;
16 import java
.util
.SortedSet
;
17 import java
.util
.TreeSet
;
19 import javax
.naming
.NamingEnumeration
;
20 import javax
.naming
.NamingException
;
21 import javax
.naming
.directory
.Attribute
;
22 import javax
.naming
.directory
.Attributes
;
23 import javax
.naming
.ldap
.LdapName
;
24 import javax
.naming
.ldap
.Rdn
;
26 import org
.argeo
.osgi
.useradmin
.UserDirectoryException
;
28 /** Basic LDIF writer */
29 public class LdifWriter
{
30 private final static Charset DEFAULT_CHARSET
= StandardCharsets
.UTF_8
;
31 private final Writer writer
;
33 /** Writer must be closed by caller */
34 public LdifWriter(Writer writer
) {
38 /** Stream must be closed by caller */
39 public LdifWriter(OutputStream out
) {
40 this(new OutputStreamWriter(out
, DEFAULT_CHARSET
));
43 public void writeEntry(LdapName name
, Attributes attributes
) throws IOException
{
46 Rdn nameRdn
= name
.getRdn(name
.size() - 1);
47 Attribute nameAttr
= attributes
.get(nameRdn
.getType());
48 if (!nameAttr
.get().equals(nameRdn
.getValue()))
49 throw new UserDirectoryException(
50 "Attribute " + nameAttr
.getID() + "=" + nameAttr
.get() + " not consistent with DN " + name
);
52 writer
.append(DN
+ ": ").append(name
.toString()).append('\n');
53 Attribute objectClassAttr
= attributes
.get(objectClass
.name());
54 if (objectClassAttr
!= null)
55 writeAttribute(objectClassAttr
);
56 attributes
: for (NamingEnumeration
<?
extends Attribute
> attrs
= attributes
.getAll(); attrs
.hasMore();) {
57 Attribute attribute
= attrs
.next();
58 if (attribute
.getID().equals(DN
) || attribute
.getID().equals(objectClass
.name()))
59 continue attributes
;// skip DN attribute
60 if (attribute
.getID().equals(member
.name()) || attribute
.getID().equals(uniqueMember
.name()))
61 continue attributes
;// skip member and uniqueMember attributes, so that they are always written last
62 writeAttribute(attribute
);
64 // write member and uniqueMember attributes last
65 for (NamingEnumeration
<?
extends Attribute
> attrs
= attributes
.getAll(); attrs
.hasMore();) {
66 Attribute attribute
= attrs
.next();
67 if (attribute
.getID().equals(member
.name()) || attribute
.getID().equals(uniqueMember
.name()))
68 writeMemberAttribute(attribute
);
72 } catch (NamingException e
) {
73 throw new UserDirectoryException("Cannot write LDIF", e
);
77 public void write(Map
<LdapName
, Attributes
> entries
) throws IOException
{
78 for (LdapName dn
: entries
.keySet())
79 writeEntry(dn
, entries
.get(dn
));
82 protected void writeAttribute(Attribute attribute
) throws NamingException
, IOException
{
83 for (NamingEnumeration
<?
> attrValues
= attribute
.getAll(); attrValues
.hasMore();) {
84 Object value
= attrValues
.next();
85 if (value
instanceof byte[]) {
86 String encoded
= Base64
.getEncoder().encodeToString((byte[]) value
);
87 writer
.append(attribute
.getID()).append(":: ").append(encoded
).append('\n');
89 writer
.append(attribute
.getID()).append(": ").append(value
.toString()).append('\n');
94 protected void writeMemberAttribute(Attribute attribute
) throws NamingException
, IOException
{
95 // Note: duplicate entries will be swallowed
96 SortedSet
<String
> values
= new TreeSet
<>();
97 for (NamingEnumeration
<?
> attrValues
= attribute
.getAll(); attrValues
.hasMore();) {
98 String value
= attrValues
.next().toString();
102 for (String value
: values
) {
103 writer
.append(attribute
.getID()).append(": ").append(value
).append('\n');