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-2015 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/** 065 * An LDAP management connection context. 066 */ 067public final class LDAPManagementContext extends DriverBasedManagementContext { 068 069 private static final class ManagementContextWrapper implements ManagementContext { 070 private final ManagementContext delegate; 071 private final List<IOException> exceptions; 072 073 private ManagementContextWrapper(ManagementContext result, List<IOException> exceptions) { 074 this.delegate = result; 075 this.exceptions = exceptions; 076 } 077 078 @Override 079 public boolean managedObjectExists(ManagedObjectPath<?, ?> path) throws ManagedObjectNotFoundException, 080 LdapException { 081 return delegate.managedObjectExists(path); 082 } 083 084 @Override 085 public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( 086 ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd) throws ManagedObjectNotFoundException, 087 LdapException { 088 return delegate.listManagedObjects(parent, rd); 089 } 090 091 @Override 092 public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( 093 ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, 094 AbstractManagedObjectDefinition<? extends C, ? extends S> d) throws ManagedObjectNotFoundException, 095 LdapException { 096 return delegate.listManagedObjects(parent, rd, d); 097 } 098 099 @Override 100 public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects( 101 ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd) 102 throws ManagedObjectNotFoundException, LdapException { 103 return delegate.listManagedObjects(parent, rd); 104 } 105 106 @Override 107 public ManagedObject<RootCfgClient> getRootConfigurationManagedObject() { 108 return delegate.getRootConfigurationManagedObject(); 109 } 110 111 @Override 112 public RootCfgClient getRootConfiguration() { 113 return delegate.getRootConfiguration(); 114 } 115 116 @Override 117 public <P> SortedSet<P> getPropertyValues(ManagedObjectPath<?, ?> path, PropertyDefinition<P> pd) 118 throws DefinitionDecodingException, LdapException, ManagedObjectNotFoundException { 119 return delegate.getPropertyValues(path, pd); 120 } 121 122 @Override 123 public <P> P getPropertyValue(ManagedObjectPath<?, ?> path, PropertyDefinition<P> pd) 124 throws DefinitionDecodingException, LdapException, ManagedObjectNotFoundException { 125 return delegate.getPropertyValue(path, pd); 126 } 127 128 @Override 129 public <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getManagedObject( 130 ManagedObjectPath<C, S> path) throws DefinitionDecodingException, ManagedObjectDecodingException, 131 ManagedObjectNotFoundException, LdapException { 132 return delegate.getManagedObject(path); 133 } 134 135 @Override 136 public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( 137 ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd, String name) 138 throws ManagedObjectNotFoundException, OperationRejectedException, LdapException { 139 return delegate.deleteManagedObject(parent, rd, name); 140 } 141 142 @Override 143 public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( 144 ManagedObjectPath<?, ?> parent, OptionalRelationDefinition<C, S> rd) 145 throws ManagedObjectNotFoundException, OperationRejectedException, LdapException { 146 return delegate.deleteManagedObject(parent, rd); 147 } 148 149 @Override 150 public <C extends ConfigurationClient, S extends Configuration> boolean deleteManagedObject( 151 ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd, String name) 152 throws ManagedObjectNotFoundException, OperationRejectedException, LdapException { 153 return delegate.deleteManagedObject(parent, rd, name); 154 } 155 156 @Override 157 public void close() throws IOException { 158 delegate.close(); 159 if (!exceptions.isEmpty()) { 160 throw exceptions.get(0); 161 } 162 } 163 } 164 165 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 166 167 /** 168 * Create a new LDAP management context using the provided LDAP connection. 169 * 170 * @param connection 171 * The LDAP connection. 172 * @param profile 173 * The LDAP profile. 174 * @return Returns the new management context. 175 */ 176 public static ManagementContext newManagementContext(Connection connection, LDAPProfile profile) { 177 Reject.ifNull(connection, profile); 178 LDAPDriver driver = new LDAPDriver(connection, profile); 179 LDAPManagementContext context = new LDAPManagementContext(driver); 180 driver.setManagementContext(context); 181 return context; 182 } 183 184 private static ManagementContext newLDIFManagementContext(final File ldifFile, final LDAPProfile profile, 185 final List<IOException> exceptions) throws IOException { 186 final BufferedReader configReader = new BufferedReader(new FileReader(ldifFile)); 187 try { 188 final MemoryBackend memoryBackend = new MemoryBackend(new LDIFEntryReader(configReader)); 189 final Connection co = new AbstractConnectionWrapper<Connection>(newInternalConnection(memoryBackend)) { 190 @Override 191 public void close() { 192 try { 193 final BufferedWriter configWriter = new BufferedWriter(new FileWriter(ldifFile)); 194 try { 195 final Iterator<Entry> entries = memoryBackend.getAll().iterator(); 196 entries.next(); // skip RootDSE 197 LDIF.copyTo(LDIF.newEntryIteratorReader(entries), new LDIFEntryWriter(configWriter)); 198 } finally { 199 configWriter.close(); 200 } 201 } catch (IOException e) { 202 if (exceptions != null) { 203 exceptions.add(e); 204 } else { 205 logger.error(LocalizableMessage.raw( 206 "IOException occured during LDIF context management close:", e)); 207 } 208 } 209 } 210 211 @Override 212 public void close(UnbindRequest request, String reason) { 213 close(); 214 } 215 }; 216 217 // We need to add the root dse entry to make the configuration framework work. 218 co.add(LDIFEntryReader.valueOfLDIFEntry("dn:", "objectClass:top", "objectClass:ds-root-dse")); 219 return LDAPManagementContext.newManagementContext(co, LDAPProfile.getInstance()); 220 } finally { 221 configReader.close(); 222 } 223 } 224 225 /** 226 * Returns a LDIF management context on the provided LDIF file. 227 * 228 * @param ldifFile 229 * The LDIF file to manage 230 * @param profile 231 * The LDAP profile 232 * @return A LDIF file management context 233 * @throws IOException 234 * If problems occurs while reading the file. 235 */ 236 public static ManagementContext newLDIFManagementContext(final File ldifFile, final LDAPProfile profile) 237 throws IOException { 238 final List<IOException> exceptions = new ArrayList<>(); 239 return new ManagementContextWrapper(newLDIFManagementContext(ldifFile, profile, exceptions), exceptions); 240 } 241 242 /** The LDAP management context driver. */ 243 private final LDAPDriver driver; 244 245 /** Private constructor. */ 246 private LDAPManagementContext(LDAPDriver driver) { 247 this.driver = driver; 248 } 249 250 /** {@inheritDoc} */ 251 @Override 252 protected Driver getDriver() { 253 return driver; 254 } 255}