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