1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.ldap.model.schema;
21
22
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30 import java.util.TreeMap;
31
32 import org.apache.directory.api.i18n.I18n;
33 import org.apache.directory.api.util.Strings;
34
35
36
37
38
39
40
41 public final class SchemaObjectSorter
42 {
43 private SchemaObjectSorter()
44 {
45 }
46
47
48
49
50
51
52
53
54 public static Iterable<AttributeType> hierarchicalOrdered( List<AttributeType> attributeTypes )
55 {
56 return new SchemaObjectIterable<>( attributeTypes, new ReferenceCallback<AttributeType>()
57 {
58 @Override
59 public Collection<String> getSuperiorOids( AttributeType at )
60 {
61 return Collections.singleton( at.getSuperiorOid() );
62 }
63 } );
64 }
65
66
67
68
69
70
71
72
73 public static Iterable<ObjectClass> sortObjectClasses( List<ObjectClass> objectClasses )
74 {
75 return new SchemaObjectIterable<>( objectClasses, new ReferenceCallback<ObjectClass>()
76 {
77 @Override
78 public Collection<String> getSuperiorOids( ObjectClass oc )
79 {
80 return oc.getSuperiorOids();
81 }
82 } );
83 }
84
85 private interface ReferenceCallback<T extends SchemaObject>
86 {
87
88 Collection<String> getSuperiorOids( T schemaObject );
89
90 }
91
92 private static final class SchemaObjectIterable<T extends SchemaObject> implements Iterable<T>
93 {
94
95 private final List<T> schemaObjects;
96 private final ReferenceCallback<T> callback;
97
98
99 private SchemaObjectIterable( List<T> schemaObjects, ReferenceCallback<T> callback )
100 {
101 this.schemaObjects = schemaObjects;
102 this.callback = callback;
103 }
104
105
106 @Override
107 public Iterator<T> iterator()
108 {
109 return new SchemaObjectIterator<>( schemaObjects, callback );
110 }
111
112 }
113
114 private static final class SchemaObjectIterator<T extends SchemaObject> implements Iterator<T>
115 {
116 private final List<T> schemaObjects;
117 private final ReferenceCallback<T> callback;
118
119 private final Map<String, String> oid2numericOid;
120 private final Map<String, T> numericOid2schemaObject;
121
122 private int loopCount;
123 private Iterator<Entry<String, T>> schemaObjectIterator;
124
125
126 private SchemaObjectIterator( List<T> schemaObjects, ReferenceCallback<T> callback )
127 {
128 this.schemaObjects = schemaObjects;
129 this.callback = callback;
130
131 this.oid2numericOid = new HashMap<>();
132 this.numericOid2schemaObject = new TreeMap<>();
133 this.loopCount = 0;
134
135 for ( T schemaObject : schemaObjects )
136 {
137 String oid = Strings.toLowerCaseAscii( schemaObject.getOid() );
138 oid2numericOid.put( oid, oid );
139
140 for ( String name : schemaObject.getNames() )
141 {
142 oid2numericOid.put( Strings.toLowerCaseAscii( name ), oid );
143 }
144
145 numericOid2schemaObject.put( oid, schemaObject );
146 }
147 }
148
149
150 @Override
151 public boolean hasNext()
152 {
153 return !numericOid2schemaObject.isEmpty();
154 }
155
156
157 @Override
158 public T next()
159 {
160 while ( !maxLoopCountReached() )
161 {
162 Iterator<Entry<String, T>> iterator = getIterator();
163
164 while ( iterator.hasNext() )
165 {
166 Entry<String, T> entry = iterator.next();
167 T schemaObject = entry.getValue();
168
169 Collection<String> superiorOids = callback.getSuperiorOids( schemaObject );
170
171
172 if ( superiorOids == null )
173 {
174 iterator.remove();
175 return schemaObject;
176 }
177
178 boolean allSuperiorsProcessed = true;
179
180 for ( String superiorOid : superiorOids )
181 {
182 if ( superiorOid == null )
183 {
184 continue;
185 }
186
187 String superiorNumeridOid = oid2numericOid.get( Strings.toLowerCaseAscii( superiorOid ) );
188
189
190 if ( superiorNumeridOid == null )
191 {
192 continue;
193 }
194
195 T superiorSchemaObject = numericOid2schemaObject.get( Strings.toLowerCaseAscii( superiorNumeridOid ) );
196
197
198 if ( superiorSchemaObject == null )
199 {
200 continue;
201 }
202
203 allSuperiorsProcessed = false;
204 break;
205 }
206
207 if ( allSuperiorsProcessed )
208 {
209 iterator.remove();
210 return schemaObject;
211 }
212 }
213 }
214 throw new IllegalStateException( I18n.err( I18n.ERR_13719_LOOP_DETECTED, numericOid2schemaObject.values() ) );
215 }
216
217
218 private Iterator<Entry<String, T>> getIterator()
219 {
220 if ( schemaObjectIterator != null && schemaObjectIterator.hasNext() )
221 {
222 return schemaObjectIterator;
223 }
224
225 if ( !maxLoopCountReached() )
226 {
227 schemaObjectIterator = numericOid2schemaObject.entrySet().iterator();
228 loopCount++;
229 return schemaObjectIterator;
230 }
231
232 throw new IllegalStateException( I18n.err( I18n.ERR_13719_LOOP_DETECTED, numericOid2schemaObject.values() ) );
233 }
234
235
236 private boolean maxLoopCountReached()
237 {
238 return loopCount > schemaObjects.size();
239 }
240
241
242 @Override
243 public void remove()
244 {
245 throw new UnsupportedOperationException();
246 }
247
248 }
249
250 }