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 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 InputStream in = resource.openStream(); 094 095 initializeSchemas( in ); 096 } 097 catch ( LdapException | IOException e ) 098 { 099 throw new RuntimeException( e ); 100 } 101 } 102 103 104 /** 105 * Instantiates a new single LDIF schema loader. 106 * 107 * @param schemaFile The Schema to load 108 */ 109 public SingleLdifSchemaLoader( String schemaFile ) 110 { 111 try 112 { 113 for ( String s : schemaObjectTypeRdns ) 114 { 115 scObjEntryMap.put( s, new HashMap<String, List<Entry>>() ); 116 } 117 118 InputStream in = Files.newInputStream( Paths.get( schemaFile ) ); 119 120 initializeSchemas( in ); 121 } 122 catch ( LdapException | IOException e ) 123 { 124 throw new RuntimeException( e ); 125 } 126 } 127 128 129 /** 130 * Instantiates a new single LDIF schema loader. 131 * 132 * @param schemaUrl The URL of the schema to load 133 */ 134 public SingleLdifSchemaLoader( URL schemaUrl ) 135 { 136 try 137 { 138 for ( String s : schemaObjectTypeRdns ) 139 { 140 scObjEntryMap.put( s, new HashMap<String, List<Entry>>() ); 141 } 142 143 InputStream in = schemaUrl.openStream(); 144 145 initializeSchemas( in ); 146 } 147 catch ( LdapException | IOException e ) 148 { 149 throw new RuntimeException( e ); 150 } 151 } 152 153 154 /** 155 * Initialize the Schema object from a Single LDIF file 156 * 157 * @param in The input stream to process 158 * @throws LdapException If the schemas can't be initialized 159 * @throws IOException If we had an issue processing the InputStream 160 */ 161 private void initializeSchemas( InputStream in ) throws LdapException, IOException 162 { 163 try ( LdifReader ldifReader = new LdifReader( in ) ) 164 { 165 Schema currentSchema = null; 166 167 while ( ldifReader.hasNext() ) 168 { 169 LdifEntry ldifEntry = ldifReader.next(); 170 String dn = ldifEntry.getDn().getName(); 171 172 if ( SCHEMA_START_PATTERN.matcher( dn ).matches() ) 173 { 174 Schema schema = getSchema( ldifEntry.getEntry() ); 175 schemaMap.put( schema.getSchemaName(), schema ); 176 currentSchema = schema; 177 } 178 else 179 { 180 if ( currentSchema == null ) 181 { 182 throw new LdapException( I18n.err( I18n.ERR_16076_NOT_A_SCHEMA_DEFINITION ) ); 183 } 184 185 loadSchemaObject( currentSchema.getSchemaName(), ldifEntry ); 186 } 187 } 188 } 189 } 190 191 192 /** 193 * Load all the schemaObjects 194 * 195 * @param schemaName The schema name 196 * @param ldifEntry The entry to load 197 */ 198 private void loadSchemaObject( String schemaName, LdifEntry ldifEntry ) 199 { 200 for ( String scObjTypeRdn : schemaObjectTypeRdns ) 201 { 202 Pattern regex = Pattern.compile( "m-oid\\s*=\\s*[0-9\\.]*\\s*" + ",\\s*ou\\s*=\\s*" + scObjTypeRdn 203 + "\\s*,\\s*cn\\s*=\\s*" + schemaName 204 + "\\s*,\\s*ou=schema\\s*", Pattern.CASE_INSENSITIVE ); 205 206 String dn = ldifEntry.getDn().getName(); 207 208 if ( regex.matcher( dn ).matches() ) 209 { 210 Map<String, List<Entry>> m = scObjEntryMap.get( scObjTypeRdn ); 211 List<Entry> entryList = m.get( schemaName ); 212 213 if ( entryList == null ) 214 { 215 entryList = new ArrayList<>(); 216 entryList.add( ldifEntry.getEntry() ); 217 m.put( schemaName, entryList ); 218 } 219 else 220 { 221 entryList.add( ldifEntry.getEntry() ); 222 } 223 224 break; 225 } 226 } 227 } 228 229 230 private List<Entry> loadSchemaObjects( String schemaObjectType, Schema... schemas ) 231 { 232 Map<String, List<Entry>> m = scObjEntryMap.get( schemaObjectType ); 233 List<Entry> atList = new ArrayList<>(); 234 235 for ( Schema s : schemas ) 236 { 237 List<Entry> preLoaded = m.get( s.getSchemaName() ); 238 239 if ( preLoaded != null ) 240 { 241 atList.addAll( preLoaded ); 242 } 243 } 244 245 return atList; 246 } 247 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override 253 public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException 254 { 255 return loadSchemaObjects( "attributetypes", schemas ); 256 } 257 258 259 /** 260 * {@inheritDoc} 261 */ 262 @Override 263 public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException 264 { 265 return loadSchemaObjects( "comparators", schemas ); 266 } 267 268 269 /** 270 * {@inheritDoc} 271 */ 272 @Override 273 public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException 274 { 275 return loadSchemaObjects( "ditContentRules", schemas ); 276 } 277 278 279 /** 280 * {@inheritDoc} 281 */ 282 @Override 283 public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException 284 { 285 return loadSchemaObjects( "ditStructureRules", schemas ); 286 } 287 288 289 /** 290 * {@inheritDoc} 291 */ 292 @Override 293 public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException 294 { 295 return loadSchemaObjects( "matchingRules", schemas ); 296 } 297 298 299 /** 300 * {@inheritDoc} 301 */ 302 @Override 303 public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException 304 { 305 return loadSchemaObjects( "matchingRuleUse", schemas ); 306 } 307 308 309 /** 310 * {@inheritDoc} 311 */ 312 @Override 313 public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException 314 { 315 return loadSchemaObjects( "nameForms", schemas ); 316 } 317 318 319 /** 320 * {@inheritDoc} 321 */ 322 @Override 323 public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException 324 { 325 return loadSchemaObjects( "normalizers", schemas ); 326 } 327 328 329 /** 330 * {@inheritDoc} 331 */ 332 @Override 333 public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException 334 { 335 return loadSchemaObjects( "objectClasses", schemas ); 336 } 337 338 339 /** 340 * {@inheritDoc} 341 */ 342 @Override 343 public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException 344 { 345 return loadSchemaObjects( "syntaxes", schemas ); 346 } 347 348 349 /** 350 * {@inheritDoc} 351 */ 352 @Override 353 public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException 354 { 355 return loadSchemaObjects( "syntaxCheckers", schemas ); 356 } 357 358} 359 360class SchemaMarker 361{ 362 /** The start marker. */ 363 private int start; 364 365 /** The end marker. */ 366 private int end; 367 368 369 SchemaMarker( int start ) 370 { 371 this.start = start; 372 } 373 374 375 public void setEnd( int end ) 376 { 377 this.end = end; 378 } 379 380 381 public int getStart() 382 { 383 return start; 384 } 385 386 387 public int getEnd() 388 { 389 return end; 390 } 391}