001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 021 package org.apache.directory.server.core.partition.ldif; 022 023 024 import java.io.File; 025 import java.io.FileFilter; 026 import java.io.FileWriter; 027 import java.util.Iterator; 028 import java.util.List; 029 import java.util.Set; 030 031 import org.apache.directory.server.core.partition.avl.AvlStore; 032 import org.apache.directory.server.i18n.I18n; 033 import org.apache.directory.server.xdbm.Index; 034 import org.apache.directory.server.xdbm.IndexCursor; 035 import org.apache.directory.server.xdbm.IndexNotFoundException; 036 import org.apache.directory.server.xdbm.Store; 037 import org.apache.directory.shared.ldap.entry.DefaultServerEntry; 038 import org.apache.directory.shared.ldap.entry.Modification; 039 import org.apache.directory.shared.ldap.entry.ModificationOperation; 040 import org.apache.directory.shared.ldap.entry.ServerEntry; 041 import org.apache.directory.shared.ldap.ldif.LdifEntry; 042 import org.apache.directory.shared.ldap.ldif.LdifReader; 043 import org.apache.directory.shared.ldap.ldif.LdifUtils; 044 import org.apache.directory.shared.ldap.name.DN; 045 import org.apache.directory.shared.ldap.name.RDN; 046 import org.apache.directory.shared.ldap.schema.SchemaManager; 047 import org.slf4j.Logger; 048 import org.slf4j.LoggerFactory; 049 050 051 /** 052 * TODO LdifStore. 053 * 054 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 055 * @version $Rev$, $Date$ 056 */ 057 public class LdifStore<E> implements Store<E, Long> 058 { 059 060 /** the working directory to use for files */ 061 private File workingDirectory; 062 063 /** true if we sync disks on every write operation */ 064 private boolean isSyncOnWrite = true; 065 066 /** in memory store used for serving the config data present in LDIF files */ 067 private AvlStore<E> wrappedStore = new AvlStore<E>(); 068 069 private SchemaManager schemaManager; 070 071 private LdifReader ldifReader; 072 073 private FileFilter dirFilter = new FileFilter() 074 { 075 public boolean accept( File dir ) 076 { 077 return dir.isDirectory(); 078 } 079 }; 080 081 private static final String CONF_FILE_EXTN = ".ldif"; 082 083 private static Logger LOG = LoggerFactory.getLogger( LdifStore.class ); 084 085 086 public void init( SchemaManager schemaManager ) throws Exception 087 { 088 this.schemaManager = schemaManager; 089 wrappedStore.init( schemaManager ); 090 091 // load the config 092 loadConfig(); 093 } 094 095 096 /** 097 * loads the configuration into the DIT from the file system 098 * @throws Exception 099 */ 100 public void loadConfig() throws Exception 101 { 102 String upsuffixDir = wrappedStore.getUpSuffix().getName().toLowerCase(); 103 File dir = new File( workingDirectory, upsuffixDir ); 104 105 if ( !dir.exists() ) 106 { 107 throw new Exception( I18n.err( I18n.ERR_631, upsuffixDir, workingDirectory.getAbsolutePath() ) ); 108 } 109 110 loadEntry( dir ); 111 } 112 113 114 /* 115 * recursively load the configuration entries 116 */ 117 private void loadEntry( File entryDir ) throws Exception 118 { 119 LOG.debug( "processing dir {}", entryDir.getName() ); 120 121 File ldifFile = new File( entryDir, entryDir.getName() + CONF_FILE_EXTN ); 122 123 try 124 { 125 126 ldifReader = new LdifReader(); 127 128 if ( ldifFile.exists() ) 129 { 130 LOG.debug( "parsing ldif file {}", ldifFile.getName() ); 131 List<LdifEntry> entries = ldifReader.parseLdifFile( ldifFile.getAbsolutePath() ); 132 133 if ( entries != null && !entries.isEmpty() ) 134 { 135 // this ldif will have only one entry 136 LdifEntry ldifEntry = entries.get( 0 ); 137 LOG.debug( "adding entry {}", ldifEntry ); 138 139 ServerEntry serverEntry = new DefaultServerEntry( schemaManager, ldifEntry.getEntry() ); 140 141 // call add on the wrapped store not on the self 142 wrappedStore.add( serverEntry ); 143 } 144 } 145 else 146 { 147 // TODO do we need to bomb out if the expected LDIF file doesn't exist 148 // I think so 149 LOG.warn( "ldif file doesn't exist {}", ldifFile.getAbsolutePath() ); 150 } 151 } 152 finally 153 { 154 ldifReader.close(); 155 } 156 157 File[] dirs = entryDir.listFiles( dirFilter ); 158 159 if ( dirs != null ) 160 { 161 for ( File f : dirs ) 162 { 163 loadEntry( f ); 164 } 165 } 166 } 167 168 169 private File getFile( DN entryDn ) 170 { 171 int size = entryDn.size(); 172 173 StringBuilder filePath = new StringBuilder(); 174 filePath.append( workingDirectory.getAbsolutePath() ).append( File.separator ); 175 176 for ( int i = 0; i < size; i++ ) 177 { 178 filePath.append( entryDn.getRdn( i ).getName().toLowerCase() ).append( File.separator ); 179 } 180 181 File dir = new File( filePath.toString() ); 182 dir.mkdirs(); 183 184 return new File( dir, entryDn.getRdn().getName().toLowerCase() + CONF_FILE_EXTN ); 185 } 186 187 188 public void add( ServerEntry entry ) throws Exception 189 { 190 wrappedStore.add( entry ); 191 192 FileWriter fw = new FileWriter( getFile( entry.getDn() ) ); 193 fw.write( LdifUtils.convertEntryToLdif( entry ) ); 194 fw.close(); 195 } 196 197 198 public void delete( Long id ) throws Exception 199 { 200 ServerEntry entry = lookup( id ); 201 LOG.warn( "deleting the entry with id {} and dn {}", id, entry.getDn() ); 202 203 LOG.warn( "having the parent id {}", getParentId( entry.getDn().getName() ) ); 204 wrappedStore.delete( id ); 205 206 if ( entry != null ) 207 { 208 File file = getFile( entry.getDn() ).getParentFile(); 209 boolean deleted = deleteFile( file ); 210 LOG.warn( "deleted file {} {}", file.getAbsoluteFile(), deleted ); 211 } 212 } 213 214 215 private boolean deleteFile( File file ) 216 { 217 if ( file.isDirectory() ) 218 { 219 File[] files = file.listFiles(); 220 for ( File f : files ) 221 { 222 deleteFile( f ); 223 } 224 } 225 226 return file.delete(); 227 } 228 229 230 public void destroy() throws Exception 231 { 232 wrappedStore.destroy(); 233 } 234 235 236 public void modify( DN dn, List<Modification> mods ) throws Exception 237 { 238 wrappedStore.modify( dn, mods ); 239 } 240 241 242 public void modify( DN dn, ModificationOperation modOp, ServerEntry mods ) throws Exception 243 { 244 wrappedStore.modify( dn, modOp, mods ); 245 } 246 247 248 public void move( DN oldChildDn, DN newParentDn, RDN newRdn, boolean deleteOldRdn ) throws Exception 249 { 250 wrappedStore.move( oldChildDn, newParentDn, newRdn, deleteOldRdn ); 251 } 252 253 254 public void move( DN oldChildDn, DN newParentDn ) throws Exception 255 { 256 wrappedStore.move( oldChildDn, newParentDn ); 257 } 258 259 260 public void rename( DN dn, RDN newRdn, boolean deleteOldRdn ) throws Exception 261 { 262 wrappedStore.rename( dn, newRdn, deleteOldRdn ); 263 } 264 265 266 public void sync() throws Exception 267 { 268 //TODO implement the File I/O here to push the update to entries to the corresponding LDIF file 269 } 270 271 272 public void setWorkingDirectory( File workingDirectory ) 273 { 274 this.workingDirectory = workingDirectory; 275 } 276 277 278 public File getWorkingDirectory() 279 { 280 return workingDirectory; 281 } 282 283 284 public void setSyncOnWrite( boolean isSyncOnWrite ) 285 { 286 this.isSyncOnWrite = isSyncOnWrite; 287 } 288 289 290 public boolean isSyncOnWrite() 291 { 292 return isSyncOnWrite; 293 } 294 295 296 public void addIndex( Index<?, E, Long> index ) throws Exception 297 { 298 wrappedStore.addIndex( index ); 299 } 300 301 302 public int count() throws Exception 303 { 304 return wrappedStore.count(); 305 } 306 307 308 public Index<String, E, Long> getAliasIndex() 309 { 310 return wrappedStore.getAliasIndex(); 311 } 312 313 314 public int getChildCount( Long id ) throws Exception 315 { 316 return wrappedStore.getChildCount( id ); 317 } 318 319 320 public String getEntryDn( Long id ) throws Exception 321 { 322 return wrappedStore.getEntryDn( id ); 323 } 324 325 326 public Long getEntryId( String dn ) throws Exception 327 { 328 return wrappedStore.getEntryId( dn ); 329 } 330 331 332 public String getEntryUpdn( Long arg0 ) throws Exception 333 { 334 return wrappedStore.getEntryUpdn( arg0 ); 335 } 336 337 338 public String getEntryUpdn( String dn ) throws Exception 339 { 340 return wrappedStore.getEntryUpdn( dn ); 341 } 342 343 344 public String getName() 345 { 346 return wrappedStore.getName(); 347 } 348 349 350 public Index<String, E, Long> getNdnIndex() 351 { 352 return wrappedStore.getNdnIndex(); 353 } 354 355 356 public Index<Long, E, Long> getOneAliasIndex() 357 { 358 return wrappedStore.getOneAliasIndex(); 359 } 360 361 362 public Index<Long, E, Long> getOneLevelIndex() 363 { 364 return wrappedStore.getOneLevelIndex(); 365 } 366 367 368 public Long getParentId( Long arg0 ) throws Exception 369 { 370 return wrappedStore.getParentId( arg0 ); 371 } 372 373 374 public Long getParentId( String dn ) throws Exception 375 { 376 return wrappedStore.getParentId( dn ); 377 } 378 379 380 public Index<String, E, Long> getPresenceIndex() 381 { 382 return wrappedStore.getPresenceIndex(); 383 } 384 385 386 public String getProperty( String propertyName ) throws Exception 387 { 388 return wrappedStore.getProperty( propertyName ); 389 } 390 391 392 public Index<Long, E, Long> getSubAliasIndex() 393 { 394 return wrappedStore.getSubAliasIndex(); 395 } 396 397 398 public Index<Long, E, Long> getSubLevelIndex() 399 { 400 return wrappedStore.getSubLevelIndex(); 401 } 402 403 404 public Index<?, E, Long> getIndex( String id ) throws IndexNotFoundException 405 { 406 return wrappedStore.getIndex( id ); 407 } 408 409 410 public Index<?, E, Long> getSystemIndex( String id ) throws IndexNotFoundException 411 { 412 return wrappedStore.getSystemIndex( id ); 413 } 414 415 416 public Index<String, E, Long> getUpdnIndex() 417 { 418 return wrappedStore.getUpdnIndex(); 419 } 420 421 422 public Index<?, E, Long> getUserIndex( String id ) throws IndexNotFoundException 423 { 424 return wrappedStore.getUserIndex( id ); 425 } 426 427 428 public Set<Index<?, E, Long>> getUserIndices() 429 { 430 return wrappedStore.getUserIndices(); 431 } 432 433 434 public boolean hasIndexOn( String id ) throws Exception 435 { 436 return wrappedStore.hasIndexOn( id ); 437 } 438 439 440 public boolean hasSystemIndexOn( String id ) throws Exception 441 { 442 return wrappedStore.hasSystemIndexOn( id ); 443 } 444 445 446 public boolean hasUserIndexOn( String id ) throws Exception 447 { 448 return wrappedStore.hasUserIndexOn( id ); 449 } 450 451 452 public boolean isInitialized() 453 { 454 return wrappedStore.isInitialized(); 455 } 456 457 458 public IndexCursor<Long, E, Long> list( Long id ) throws Exception 459 { 460 return wrappedStore.list( id ); 461 } 462 463 464 public ServerEntry lookup( Long id ) throws Exception 465 { 466 return wrappedStore.lookup( id ); 467 } 468 469 470 public void setAliasIndex( Index<String, E, Long> index ) throws Exception 471 { 472 wrappedStore.setAliasIndex( index ); 473 } 474 475 476 public void setName( String name ) 477 { 478 wrappedStore.setName( name ); 479 } 480 481 482 public void setNdnIndex( Index<String, E, Long> index ) throws Exception 483 { 484 wrappedStore.setNdnIndex( index ); 485 } 486 487 488 public void setOneAliasIndex( Index<Long, E, Long> index ) throws Exception 489 { 490 wrappedStore.setOneAliasIndex( index ); 491 } 492 493 494 public void setOneLevelIndex( Index<Long, E, Long> index ) throws Exception 495 { 496 wrappedStore.setOneLevelIndex( index ); 497 } 498 499 500 public void setPresenceIndex( Index<String, E, Long> index ) throws Exception 501 { 502 wrappedStore.setPresenceIndex( index ); 503 } 504 505 506 public void setProperty( String propertyName, String propertyValue ) throws Exception 507 { 508 wrappedStore.setProperty( propertyName, propertyValue ); 509 } 510 511 512 public void setSubAliasIndex( Index<Long, E, Long> index ) throws Exception 513 { 514 wrappedStore.setSubAliasIndex( index ); 515 } 516 517 518 public void setSubLevelIndex( Index<Long, E, Long> index ) throws Exception 519 { 520 wrappedStore.setSubLevelIndex( index ); 521 } 522 523 524 public void setUpdnIndex( Index<String, E, Long> index ) throws Exception 525 { 526 wrappedStore.setUpdnIndex( index ); 527 } 528 529 530 public Iterator<String> systemIndices() 531 { 532 return wrappedStore.systemIndices(); 533 } 534 535 536 public Iterator<String> userIndices() 537 { 538 return wrappedStore.userIndices(); 539 } 540 541 542 //TODO manage the cache size?? 543 public int getCacheSize() 544 { 545 return wrappedStore.getCacheSize(); 546 } 547 548 549 public Index<String, E, Long> getEntryCsnIndex() 550 { 551 return wrappedStore.getEntryCsnIndex(); 552 } 553 554 555 public Index<String, E, Long> getEntryUuidIndex() 556 { 557 return wrappedStore.getEntryUuidIndex(); 558 } 559 560 561 public Index<String, E, Long> getObjectClassIndex() 562 { 563 return wrappedStore.getObjectClassIndex(); 564 } 565 566 567 public DN getSuffix() 568 { 569 return wrappedStore.getSuffix(); 570 } 571 572 573 public String getSuffixDn() 574 { 575 return wrappedStore.getSuffixDn(); 576 } 577 578 579 public DN getUpSuffix() 580 { 581 return wrappedStore.getUpSuffix(); 582 } 583 584 585 public void setCacheSize( int size ) 586 { 587 wrappedStore.setCacheSize( size ); 588 } 589 590 591 public void setUserIndices( Set<Index<?, E, Long>> userIndices ) 592 { 593 wrappedStore.setUserIndices( userIndices ); 594 } 595 596 597 public void setSuffixDn( String suffixDn ) 598 { 599 wrappedStore.setSuffixDn( suffixDn ); 600 } 601 602 603 public void setEntryCsnIndex( Index<String, E, Long> index ) throws Exception 604 { 605 wrappedStore.setEntryCsnIndex( index ); 606 } 607 608 609 public void setEntryUuidIndex( Index<String, E, Long> index ) throws Exception 610 { 611 wrappedStore.setEntryUuidIndex( index ); 612 } 613 614 615 public void setObjectClassIndex( Index<String, E, Long> index ) throws Exception 616 { 617 wrappedStore.setObjectClassIndex( index ); 618 } 619 620 621 public Long getDefaultId() 622 { 623 return 1L; 624 } 625 626 }