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 * https://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 021package org.apache.directory.api.ldap.schema.loader; 022 023 024import java.io.IOException; 025import java.io.InputStream; 026import java.net.URL; 027import java.nio.file.Files; 028import java.nio.file.Paths; 029import java.util.ArrayList; 030import java.util.HashMap; 031import java.util.List; 032import java.util.Map; 033import java.util.regex.Pattern; 034 035import org.apache.directory.api.i18n.I18n; 036import org.apache.directory.api.ldap.model.entry.Entry; 037import org.apache.directory.api.ldap.model.exception.LdapException; 038import org.apache.directory.api.ldap.model.ldif.LdifEntry; 039import org.apache.directory.api.ldap.model.ldif.LdifReader; 040import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader; 041import org.apache.directory.api.ldap.model.schema.registries.Schema; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045 046/** 047 * A schema loader based on a single monolithic ldif file containing all the schema partition elements 048 * 049 * Performs better than any other existing LDIF schema loaders. NOT DOCUMENTED atm 050 * 051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 052 */ 053public class SingleLdifSchemaLoader extends AbstractSchemaLoader 054{ 055 /** 056 * Pattern for start of schema Dn. 057 * java.util.regex.Pattern is immutable so only one instance is needed for all uses. 058 */ 059 private static final Pattern SCHEMA_START_PATTERN = Pattern 060 .compile( "cn\\s*=\\s*[a-z0-9-_]*\\s*,\\s*ou\\s*=\\s*schema" ); 061 062 /** The logger. */ 063 private static final Logger LOG = LoggerFactory.getLogger( SingleLdifSchemaLoader.class ); 064 065 /** The schema object Rdn attribute types. */ 066 private String[] schemaObjectTypeRdns = new String[] 067 { "attributetypes", "comparators", "ditContentRules", "ditStructureRules", "matchingRules", "matchingRuleUse", 068 "nameForms", "normalizers", "objectClasses", "syntaxes", "syntaxCheckers" }; 069 070 /** The map containing ... */ 071 private Map<String, Map<String, List<Entry>>> scObjEntryMap = new HashMap<>(); 072 073 074 /** 075 * Instantiates a new single LDIF schema loader. 076 */ 077 public SingleLdifSchemaLoader() 078 { 079 try 080 { 081 URL resource = getClass().getClassLoader().getResource( "schema-all.ldif" ); 082 083 if ( LOG.isDebugEnabled() ) 084 { 085 LOG.debug( I18n.msg( I18n.MSG_16012_URL_SCHEMA_ALL_LDIF, resource ) ); 086 } 087 088 for ( String s : schemaObjectTypeRdns ) 089 { 090 scObjEntryMap.put( s, new HashMap<String, List<Entry>>() ); 091 } 092 093 try ( InputStream in = resource.openStream() ) 094 { 095 initializeSchemas( in ); 096 } 097 } 098 catch ( LdapException | IOException e ) 099 { 100 throw new RuntimeException( e ); 101 } 102 } 103 104 105 /** 106 * Instantiates a new single LDIF schema loader. 107 * 108 * @param schemaFile The Schema to load 109 */ 110 public SingleLdifSchemaLoader( String schemaFile ) 111 { 112 try 113 { 114 for ( String s : schemaObjectTypeRdns ) 115 { 116 scObjEntryMap.put( s, new HashMap<String, List<Entry>>() ); 117 } 118 119 try ( InputStream in = Files.newInputStream( Paths.get( schemaFile ) ) ) 120 { 121 initializeSchemas( in ); 122 } 123 } 124 catch ( LdapException | IOException e ) 125 { 126 throw new RuntimeException( e ); 127 } 128 } 129 130 131 /** 132 * Instantiates a new single LDIF schema loader. 133 * 134 * @param schemaUrl The URL of the schema to load 135 */ 136 public SingleLdifSchemaLoader( URL schemaUrl ) 137 { 138 try 139 { 140 for ( String s : schemaObjectTypeRdns ) 141 { 142 scObjEntryMap.put( s, new HashMap<String, List<Entry>>() ); 143 } 144 145 try ( InputStream in = schemaUrl.openStream() ) 146 { 147 initializeSchemas( in ); 148 } 149 } 150 catch ( LdapException | IOException e ) 151 { 152 throw new RuntimeException( e ); 153 } 154 } 155 156 157 /** 158 * Initialize the Schema object from a Single LDIF file 159 * 160 * @param in The input stream to process 161 * @throws LdapException If the schemas can't be initialized 162 * @throws IOException If we had an issue processing the InputStream 163 */ 164 private void initializeSchemas( InputStream in ) throws LdapException, IOException 165 { 166 try ( LdifReader ldifReader = new LdifReader( in ) ) 167 { 168 Schema currentSchema = null; 169 170 while ( ldifReader.hasNext() ) 171 { 172 LdifEntry ldifEntry = ldifReader.next(); 173 String dn = ldifEntry.getDn().getName(); 174 175 if ( SCHEMA_START_PATTERN.matcher( dn ).matches() ) 176 { 177 Schema schema = getSchema( ldifEntry.getEntry() ); 178 schemaMap.put( schema.getSchemaName(), schema ); 179 currentSchema = schema; 180 } 181 else 182 { 183 if ( currentSchema == null ) 184 { 185 throw new LdapException( I18n.err( I18n.ERR_16076_NOT_A_SCHEMA_DEFINITION ) ); 186 } 187 188 loadSchemaObject( currentSchema.getSchemaName(), ldifEntry ); 189 } 190 } 191 } 192 } 193 194 195 /** 196 * Load all the schemaObjects 197 * 198 * @param schemaName The schema name 199 * @param ldifEntry The entry to load 200 */ 201 private void loadSchemaObject( String schemaName, LdifEntry ldifEntry ) 202 { 203 for ( String scObjTypeRdn : schemaObjectTypeRdns ) 204 { 205 Pattern regex = Pattern.compile( "m-oid\\s*=\\s*[0-9\\.]*\\s*" + ",\\s*ou\\s*=\\s*" + scObjTypeRdn 206 + "\\s*,\\s*cn\\s*=\\s*" + schemaName 207 + "\\s*,\\s*ou=schema\\s*", Pattern.CASE_INSENSITIVE ); 208 209 String dn = ldifEntry.getDn().getName(); 210 211 if ( regex.matcher( dn ).matches() ) 212 { 213 Map<String, List<Entry>> m = scObjEntryMap.get( scObjTypeRdn ); 214 List<Entry> entryList = m.get( schemaName ); 215 216 if ( entryList == null ) 217 { 218 entryList = new ArrayList<>(); 219 entryList.add( ldifEntry.getEntry() ); 220 m.put( schemaName, entryList ); 221 } 222 else 223 { 224 entryList.add( ldifEntry.getEntry() ); 225 } 226 227 break; 228 } 229 } 230 } 231 232 233 private List<Entry> loadSchemaObjects( String schemaObjectType, Schema... schemas ) 234 { 235 Map<String, List<Entry>> m = scObjEntryMap.get( schemaObjectType ); 236 List<Entry> atList = new ArrayList<>(); 237 238 for ( Schema s : schemas ) 239 { 240 List<Entry> preLoaded = m.get( s.getSchemaName() ); 241 242 if ( preLoaded != null ) 243 { 244 atList.addAll( preLoaded ); 245 } 246 } 247 248 return atList; 249 } 250 251 252 /** 253 * {@inheritDoc} 254 */ 255 @Override 256 public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException 257 { 258 return loadSchemaObjects( "attributetypes", schemas ); 259 } 260 261 262 /** 263 * {@inheritDoc} 264 */ 265 @Override 266 public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException 267 { 268 return loadSchemaObjects( "comparators", schemas ); 269 } 270 271 272 /** 273 * {@inheritDoc} 274 */ 275 @Override 276 public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException 277 { 278 return loadSchemaObjects( "ditContentRules", schemas ); 279 } 280 281 282 /** 283 * {@inheritDoc} 284 */ 285 @Override 286 public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException 287 { 288 return loadSchemaObjects( "ditStructureRules", schemas ); 289 } 290 291 292 /** 293 * {@inheritDoc} 294 */ 295 @Override 296 public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException 297 { 298 return loadSchemaObjects( "matchingRules", schemas ); 299 } 300 301 302 /** 303 * {@inheritDoc} 304 */ 305 @Override 306 public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException 307 { 308 return loadSchemaObjects( "matchingRuleUse", schemas ); 309 } 310 311 312 /** 313 * {@inheritDoc} 314 */ 315 @Override 316 public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException 317 { 318 return loadSchemaObjects( "nameForms", schemas ); 319 } 320 321 322 /** 323 * {@inheritDoc} 324 */ 325 @Override 326 public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException 327 { 328 return loadSchemaObjects( "normalizers", schemas ); 329 } 330 331 332 /** 333 * {@inheritDoc} 334 */ 335 @Override 336 public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException 337 { 338 return loadSchemaObjects( "objectClasses", schemas ); 339 } 340 341 342 /** 343 * {@inheritDoc} 344 */ 345 @Override 346 public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException 347 { 348 return loadSchemaObjects( "syntaxes", schemas ); 349 } 350 351 352 /** 353 * {@inheritDoc} 354 */ 355 @Override 356 public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException 357 { 358 return loadSchemaObjects( "syntaxCheckers", schemas ); 359 } 360 361} 362 363class SchemaMarker 364{ 365 /** The start marker. */ 366 private int start; 367 368 /** The end marker. */ 369 private int end; 370 371 372 SchemaMarker( int start ) 373 { 374 this.start = start; 375 } 376 377 378 public void setEnd( int end ) 379 { 380 this.end = end; 381 } 382 383 384 public int getStart() 385 { 386 return start; 387 } 388 389 390 public int getEnd() 391 { 392 return end; 393 } 394}