001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008 Sun Microsystems, Inc. 015 * Portions copyright 2014-2016 ForgeRock AS. 016 */ 017 018package org.forgerock.opendj.config.client.ldap; 019 020import static org.forgerock.opendj.ldap.Connections.*; 021 022import java.io.BufferedReader; 023import java.io.BufferedWriter; 024import java.io.File; 025import java.io.FileReader; 026import java.io.FileWriter; 027import java.io.IOException; 028import java.util.ArrayList; 029import java.util.Iterator; 030import java.util.List; 031import java.util.SortedSet; 032 033import org.forgerock.i18n.LocalizableMessage; 034import org.forgerock.i18n.slf4j.LocalizedLogger; 035import org.forgerock.opendj.config.AbstractManagedObjectDefinition; 036import org.forgerock.opendj.config.Configuration; 037import org.forgerock.opendj.config.ConfigurationClient; 038import org.forgerock.opendj.config.DefinitionDecodingException; 039import org.forgerock.opendj.config.InstantiableRelationDefinition; 040import org.forgerock.opendj.config.LDAPProfile; 041import org.forgerock.opendj.config.ManagedObjectNotFoundException; 042import org.forgerock.opendj.config.ManagedObjectPath; 043import org.forgerock.opendj.config.OptionalRelationDefinition; 044import org.forgerock.opendj.config.PropertyDefinition; 045import org.forgerock.opendj.config.SetRelationDefinition; 046import org.forgerock.opendj.config.client.DriverBasedManagementContext; 047import org.forgerock.opendj.config.client.ManagedObject; 048import org.forgerock.opendj.config.client.ManagedObjectDecodingException; 049import org.forgerock.opendj.config.client.ManagementContext; 050import org.forgerock.opendj.config.client.OperationRejectedException; 051import org.forgerock.opendj.config.client.spi.Driver; 052import org.forgerock.opendj.ldap.AbstractConnectionWrapper; 053import org.forgerock.opendj.ldap.Connection; 054import org.forgerock.opendj.ldap.Entry; 055import org.forgerock.opendj.ldap.LdapException; 056import org.forgerock.opendj.ldap.MemoryBackend; 057import org.forgerock.opendj.ldap.requests.UnbindRequest; 058import org.forgerock.opendj.ldif.LDIF; 059import org.forgerock.opendj.ldif.LDIFEntryReader; 060import org.forgerock.opendj.ldif.LDIFEntryWriter; 061import org.forgerock.opendj.server.config.client.RootCfgClient; 062import org.forgerock.util.Reject; 063 064/** An LDAP management connection context. */ 065public final class LDAPManagementContext extends DriverBasedManagementContext { 066 067 private static final class ManagementContextWrapper implements ManagementContext { 068 private final ManagementContext delegate; 069 private final List<IOException> exceptions; 070 071 private ManagementContextWrapper(ManagementContext result, List<IOException> exceptions) { 072 this.delegate = result; 073 this.exceptions = exceptions; 074 } 075 076 @Override 077 public boolean managedObjectExists(ManagedObjectPath<?, ?> path) throws ManagedObjectNotFoundException, 078 LdapException { 079 return delegate.managedObjectExists(path); 080 } 081 082 @Override 083 public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( 084 ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd) throws ManagedObjectNotFoundException, 085 LdapException { 086 return delegate.listManagedObjects(parent, rd); 087 } 088 089 @Override 090 public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( 091 ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, 092 AbstractManagedObjectDefinition<? extends C, ? extends S> d) throws ManagedObjectNotFoundException, 093 LdapException { 094 return delegate.listManagedObjects(parent, rd, d); 095 } 096 097 @Override 098 public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( 099 ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd) 100 throws ManagedObjectNotFoundException, LdapException { 101 return delegate.listManagedObjects(parent, rd); 102 } 103 104 @Override 105 public ManagedObject<RootCfgClient> getRootConfigurationManagedObject() { 106 return delegate.getRootConfigurationManagedObject(); 107 } 108 109 @Override 110 public RootCfgClient getRootConfiguration() { 111 return delegate.getRootConfiguration(); 112 } 113 114 @Override 115 public <P> SortedSet<P> getPropertyValues(ManagedObjectPath<?, ?> path, PropertyDefinition<P> pd) 116 throws DefinitionDecodingException, LdapException, ManagedObjectNotFoundException { 117 return delegate.getPropertyValues(path, pd); 118 } 119 120 @Override 121 public <P> P getPropertyValue(ManagedObjectPath<?, ?> path, PropertyDefinition<P> pd) 122 throws DefinitionDecodingException, LdapException, ManagedObjectNotFoundException { 123 return delegate.getPropertyValue(path, pd); 124 } 125 126 @Override 127 public <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getManagedObject( 128 ManagedObjectPath<C, S> path) throws DefinitionDecodingException, ManagedObjectDecodingException, 129 ManagedObjectNotFoundException, LdapException { 130 return delegate.getManagedObject(path); 131 } 132 133 @Override 134 public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( 135 ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd, String name) 136 throws ManagedObjectNotFoundException, OperationRejectedException, LdapException { 137 return delegate.deleteManagedObject(parent, rd, name); 138 } 139 140 @Override 141 public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( 142 ManagedObjectPath<?, ?> parent, OptionalRelationDefinition<C, S> rd) 143 throws ManagedObjectNotFoundException, OperationRejectedException, LdapException { 144 return delegate.deleteManagedObject(parent, rd); 145 } 146 147 @Override 148 public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( 149 ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, String name) 150 throws ManagedObjectNotFoundException, OperationRejectedException, LdapException { 151 return delegate.deleteManagedObject(parent, rd, name); 152 } 153 154 @Override 155 public void close() throws IOException { 156 delegate.close(); 157 if (!exceptions.isEmpty()) { 158 throw exceptions.get(0); 159 } 160 } 161 } 162 163 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 164 165 /** 166 * Create a new LDAP management context using the provided LDAP connection. 167 * 168 * @param connection 169 * The LDAP connection. 170 * @param profile 171 * The LDAP profile. 172 * @return Returns the new management context. 173 */ 174 public static ManagementContext newManagementContext(Connection connection, LDAPProfile profile) { 175 Reject.ifNull(connection, profile); 176 LDAPDriver driver = new LDAPDriver(connection, profile); 177 LDAPManagementContext context = new LDAPManagementContext(driver); 178 driver.setManagementContext(context); 179 return context; 180 } 181 182 private static ManagementContext newLDIFManagementContext(final File ldifFile, final List<IOException> exceptions) 183 throws IOException { 184 try (final FileReader fileReader = new FileReader(ldifFile); 185 final BufferedReader configReader = new BufferedReader(fileReader)) { 186 final MemoryBackend memoryBackend = new MemoryBackend(new LDIFEntryReader(configReader)); 187 final Connection co = new AbstractConnectionWrapper<Connection>(newInternalConnection(memoryBackend)) { 188 @Override 189 public void close() { 190 try (final FileWriter fileWriter = new FileWriter(ldifFile); 191 final BufferedWriter configWriter = new BufferedWriter(fileWriter)) { 192 final Iterator<Entry> entries = memoryBackend.getAll().iterator(); 193 entries.next(); // skip RootDSE 194 LDIF.copyTo(LDIF.newEntryIteratorReader(entries), new LDIFEntryWriter(configWriter)); 195 } catch (IOException e) { 196 if (exceptions != null) { 197 exceptions.add(e); 198 } else { 199 logger.error(LocalizableMessage.raw( 200 "IOException occured during LDIF context management close:", e)); 201 } 202 } 203 } 204 205 @Override 206 public void close(UnbindRequest request, String reason) { 207 close(); 208 } 209 }; 210 211 // We need to add the root dse entry to make the configuration framework work. 212 co.add(LDIFEntryReader.valueOfLDIFEntry("dn:", "objectClass:top", "objectClass:ds-root-dse")); 213 return LDAPManagementContext.newManagementContext(co, LDAPProfile.getInstance()); 214 } 215 } 216 217 /** 218 * Returns a LDIF management context on the provided LDIF file. 219 * 220 * @param ldifFile 221 * The LDIF file to manage 222 * @return A LDIF file management context 223 * @throws IOException 224 * If problems occurs while reading the file. 225 */ 226 public static ManagementContext newLDIFManagementContext(final File ldifFile) throws IOException { 227 final List<IOException> exceptions = new ArrayList<>(); 228 return new ManagementContextWrapper(newLDIFManagementContext(ldifFile, exceptions), exceptions); 229 } 230 231 /** The LDAP management context driver. */ 232 private final LDAPDriver driver; 233 234 /** Private constructor. */ 235 private LDAPManagementContext(LDAPDriver driver) { 236 this.driver = driver; 237 } 238 239 @Override 240 protected Driver getDriver() { 241 return driver; 242 } 243}