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