| Total Complexity | 90 | 
| Total Lines | 654 | 
| Duplicated Lines | 4.43 % | 
| Changes | 1 | ||
| Bugs | 0 | Features | 0 | 
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like de.tudresden.inf.lat.jcel.core.algorithm.rulebased.RuleBasedProcessor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | /*  | 
            ||
| 90 | public class RuleBasedProcessor implements Processor { | 
            ||
| 91 | |||
| 92 | 	private class WorkerThreadR extends Thread { | 
            ||
| 93 | @Override  | 
            ||
| 94 | 		public void run() { | 
            ||
| 95 | 			while (RuleBasedProcessor.this.status.getNumberOfREntries() > 0) { | 
            ||
| 96 | 				while (RuleBasedProcessor.this.status.getNumberOfREntries() > 0) { | 
            ||
| 97 | processREntries();  | 
            ||
| 98 | }  | 
            ||
| 99 | 				try { | 
            ||
| 100 | Thread.sleep(threadWaitingTime);  | 
            ||
| 101 | 				} catch (InterruptedException e) { | 
            ||
| 102 | throw new IllegalStateException(e);  | 
            ||
| 103 | }  | 
            ||
| 104 | }  | 
            ||
| 105 | }  | 
            ||
| 106 | }  | 
            ||
| 107 | |||
| 108 | 	private class WorkerThreadS extends Thread { | 
            ||
| 109 | @Override  | 
            ||
| 110 | 		public void run() { | 
            ||
| 111 | 			while (RuleBasedProcessor.this.status.getNumberOfSEntries() > 0) { | 
            ||
| 112 | 				while (RuleBasedProcessor.this.status.getNumberOfSEntries() > 0) { | 
            ||
| 113 | processSEntries();  | 
            ||
| 114 | }  | 
            ||
| 115 | 				try { | 
            ||
| 116 | Thread.sleep(threadWaitingTime);  | 
            ||
| 117 | 				} catch (InterruptedException e) { | 
            ||
| 118 | throw new IllegalStateException(e);  | 
            ||
| 119 | }  | 
            ||
| 120 | }  | 
            ||
| 121 | }  | 
            ||
| 122 | }  | 
            ||
| 123 | |||
| 124 | private static final Logger logger = Logger.getLogger(RuleBasedProcessor.class.getName());  | 
            ||
| 125 | |||
| 126 | private static final long loggingFrequency = 0x1000000;  | 
            ||
| 127 | private static final long threadWaitingTime = 0x20;  | 
            ||
| 128 | private static final Integer topClassId = IntegerEntityManager.topClassId;  | 
            ||
| 129 | |||
| 130 | private RChain chainR = null;  | 
            ||
| 131 | private SChain chainS = null;  | 
            ||
| 132 | private IntegerHierarchicalGraph classHierarchy = null;  | 
            ||
| 133 | private IntegerHierarchicalGraph dataPropertyHierarchy = null;  | 
            ||
| 134 | private OptMap<Integer, Set<Integer>> directTypes = null;  | 
            ||
| 135 | private final IntegerEntityManager entityManager;  | 
            ||
| 136 | private final NormalizedIntegerAxiomFactory factory;  | 
            ||
| 137 | private boolean isReady = false;  | 
            ||
| 138 | private long iteration = 0;  | 
            ||
| 139 | private long loggingCount = loggingFrequency;  | 
            ||
| 140 | private final boolean multiThreadedMode = false;  | 
            ||
| 141 | private IntegerHierarchicalGraph objectPropertyHierarchy = null;  | 
            ||
| 142 | private OptMap<Integer, Set<Integer>> sameIndividualMap = null;  | 
            ||
| 143 | private ClassifierStatusImpl status = null;  | 
            ||
| 144 | private WorkerThreadR threadR1 = null;  | 
            ||
| 145 | private WorkerThreadR threadR2 = null;  | 
            ||
| 146 | private WorkerThreadS threadS1 = null;  | 
            ||
| 147 | private WorkerThreadS threadS2 = null;  | 
            ||
| 148 | |||
| 149 | /**  | 
            ||
| 150 | * Constructs a new rule-based processor.  | 
            ||
| 151 | *  | 
            ||
| 152 | * @param originalObjectProperties  | 
            ||
| 153 | * set of original object properties  | 
            ||
| 154 | * @param originalClasses  | 
            ||
| 155 | * set of original classes  | 
            ||
| 156 | * @param normalizedAxiomSet  | 
            ||
| 157 | * set of normalized axioms  | 
            ||
| 158 | * @param expressivity  | 
            ||
| 159 | * expressivity  | 
            ||
| 160 | * @param factory  | 
            ||
| 161 | * factory of normalized integer axioms  | 
            ||
| 162 | * @param entityManager  | 
            ||
| 163 | * entity manager  | 
            ||
| 164 | */  | 
            ||
| 165 | public RuleBasedProcessor(Set<Integer> originalObjectProperties, Set<Integer> originalClasses,  | 
            ||
| 166 | Set<NormalizedIntegerAxiom> normalizedAxiomSet, OntologyExpressivity expressivity,  | 
            ||
| 167 | 			NormalizedIntegerAxiomFactory factory, IntegerEntityManager entityManager) { | 
            ||
| 168 | Objects.requireNonNull(originalObjectProperties);  | 
            ||
| 169 | Objects.requireNonNull(originalClasses);  | 
            ||
| 170 | Objects.requireNonNull(normalizedAxiomSet);  | 
            ||
| 171 | Objects.requireNonNull(expressivity);  | 
            ||
| 172 | Objects.requireNonNull(factory);  | 
            ||
| 173 | Objects.requireNonNull(entityManager);  | 
            ||
| 174 | this.factory = factory;  | 
            ||
| 175 | this.entityManager = entityManager;  | 
            ||
| 176 | |||
| 177 | CompletionRuleChainSelector selector = new CompletionRuleChainSelector(expressivity);  | 
            ||
| 178 | selector.activateProfiler();  | 
            ||
| 179 | this.chainR = selector.getRChain();  | 
            ||
| 180 | this.chainS = selector.getSChain();  | 
            ||
| 181 | |||
| 182 | preProcess(createExtendedOntology(originalObjectProperties, originalClasses, normalizedAxiomSet));  | 
            ||
| 183 | }  | 
            ||
| 184 | |||
| 185 | 	public void addAxioms(Set<NormalizedIntegerAxiom> normalizedAxiomSet) { | 
            ||
| 186 | Objects.requireNonNull(normalizedAxiomSet);  | 
            ||
| 187 | 		logger.fine("adding axioms ..."); | 
            ||
| 188 | this.status.getExtendedOntology().load(normalizedAxiomSet);  | 
            ||
| 189 | preProcess(this.status.getExtendedOntology());  | 
            ||
| 190 | 		logger.fine("processor reset."); | 
            ||
| 191 | }  | 
            ||
| 192 | |||
| 193 | /**  | 
            ||
| 194 | * @param hierarchicalGraph  | 
            ||
| 195 | * graph containing direct subsumers  | 
            ||
| 196 | * @return a map with all the direct types for each individual.  | 
            ||
| 197 | */  | 
            ||
| 198 | 	private OptMap<Integer, Set<Integer>> computeDirectTypes(IntegerHierarchicalGraph hierarchicalGraph) { | 
            ||
| 199 | OptMap<Integer, Set<Integer>> ret = new OptMapImpl<>(new HashMap<>());  | 
            ||
| 200 | Set<Integer> individuals = getEntityManager().getIndividuals();  | 
            ||
| 201 | 		individuals.forEach(indiv -> { | 
            ||
| 202 | Set<Integer> subsumers = hierarchicalGraph.getParents(getEntityManager().getAuxiliaryNominal(indiv).get());  | 
            ||
| 203 | 			subsumers.forEach(elem -> { | 
            ||
| 204 | 				if (getEntityManager().getAuxiliaryNominals().contains(elem)) { | 
            ||
| 205 | 					throw new IllegalStateException("An individual has another individual as direct subsumer."); | 
            ||
| 206 | }  | 
            ||
| 207 | });  | 
            ||
| 208 | ret.put(indiv, Collections.unmodifiableSet(subsumers));  | 
            ||
| 209 | });  | 
            ||
| 210 | return ret;  | 
            ||
| 211 | }  | 
            ||
| 212 | |||
| 213 | /**  | 
            ||
| 214 | * This is a graph reachability algorithm that returns all elements d  | 
            ||
| 215 | * reachable from an element c using a path where each segment is from any  | 
            ||
| 216 | * of the properties in R.  | 
            ||
| 217 | *  | 
            ||
| 218 | * @param c  | 
            ||
| 219 | * first element in the path  | 
            ||
| 220 | * @return the set of all nodes reachable from c using any possible segment  | 
            ||
| 221 | */  | 
            ||
| 222 | 	private Set<Integer> computeReachability(Integer c) { | 
            ||
| 223 | Set<Integer> ret = new HashSet<>();  | 
            ||
| 224 | Set<Integer> toVisit = new HashSet<>();  | 
            ||
| 225 | toVisit.add(c);  | 
            ||
| 226 | 		while (!toVisit.isEmpty()) { | 
            ||
| 227 | Integer elem = toVisit.iterator().next();  | 
            ||
| 228 | toVisit.remove(elem);  | 
            ||
| 229 | ret.add(elem);  | 
            ||
| 230 | Set<Integer> newToVisit = new HashSet<>();  | 
            ||
| 231 | 			this.status.getObjectPropertiesByFirst(elem).forEach(r -> { | 
            ||
| 232 | IntegerBinaryRelation relation = this.status.getRelationSet().get(r);  | 
            ||
| 233 | newToVisit.addAll(relation.getByFirst(elem));  | 
            ||
| 234 | });  | 
            ||
| 235 | newToVisit.removeAll(ret);  | 
            ||
| 236 | toVisit.addAll(newToVisit);  | 
            ||
| 237 | }  | 
            ||
| 238 | return ret;  | 
            ||
| 239 | }  | 
            ||
| 240 | |||
| 241 | 	private Set<Integer> computeReachability(Integer c, OptMap<Integer, Set<Integer>> reachableNodeCache) { | 
            ||
| 242 | Optional<Set<Integer>> optReachableNodes = reachableNodeCache.get(c);  | 
            ||
| 243 | 		if (!optReachableNodes.isPresent()) { | 
            ||
| 244 | optReachableNodes = Optional.of(computeReachability(c));  | 
            ||
| 245 | reachableNodeCache.put(c, optReachableNodes.get());  | 
            ||
| 246 | }  | 
            ||
| 247 | return optReachableNodes.get();  | 
            ||
| 248 | }  | 
            ||
| 249 | |||
| 250 | View Code Duplication | 	private OptMap<Integer, Set<Integer>> computeSameIndividualMap(IntegerHierarchicalGraph hierarchicalGraph) { | 
            |
| 
                                                                                                    
                        
                         | 
                |||
| 251 | OptMap<Integer, Set<Integer>> ret = new OptMapImpl<>(new HashMap<>());  | 
            ||
| 252 | Set<Integer> individuals = getEntityManager().getIndividuals();  | 
            ||
| 253 | 		individuals.forEach(indiv -> { | 
            ||
| 254 | Set<Integer> equivalentClasses = hierarchicalGraph  | 
            ||
| 255 | .getEquivalents(getEntityManager().getAuxiliaryNominal(indiv).get());  | 
            ||
| 256 | Set<Integer> equivalents = new HashSet<>();  | 
            ||
| 257 | 			equivalentClasses.forEach(elem -> { | 
            ||
| 258 | 				if (getEntityManager().getAuxiliaryNominals().contains(elem)) { | 
            ||
| 259 | equivalents.add(getEntityManager().getIndividual(elem).get());  | 
            ||
| 260 | }  | 
            ||
| 261 | });  | 
            ||
| 262 | ret.put(indiv, Collections.unmodifiableSet(equivalents));  | 
            ||
| 263 | });  | 
            ||
| 264 | return ret;  | 
            ||
| 265 | }  | 
            ||
| 266 | |||
| 267 | /**  | 
            ||
| 268 | * Convenience method to create a map entry. This method returns a map  | 
            ||
| 269 | * entry.  | 
            ||
| 270 | *  | 
            ||
| 271 | * @param key  | 
            ||
| 272 | * key  | 
            ||
| 273 | * @param value  | 
            ||
| 274 | * value  | 
            ||
| 275 | * @return a map entry created using the parameters  | 
            ||
| 276 | */  | 
            ||
| 277 | 	private Map.Entry<String, String> createEntry(String key, String value) { | 
            ||
| 278 | return new AbstractMap.SimpleEntry<String, String>(key, value);  | 
            ||
| 279 | }  | 
            ||
| 280 | |||
| 281 | private ExtendedOntology createExtendedOntology(Set<Integer> originalObjectPropertySet,  | 
            ||
| 282 | 			Set<Integer> originalClassSet, Set<NormalizedIntegerAxiom> axioms) { | 
            ||
| 283 | SubPropertyNormalizer subPropNormalizer = new SubPropertyNormalizer(getOntologyObjectFactory(),  | 
            ||
| 284 | getEntityManager());  | 
            ||
| 285 | Set<NormalizedIntegerAxiom> saturatedNormalizedAxiomSet = subPropNormalizer.apply(axioms);  | 
            ||
| 286 | ExtendedOntology extendedOntology = new ExtendedOntologyImpl();  | 
            ||
| 287 | extendedOntology.load(saturatedNormalizedAxiomSet);  | 
            ||
| 288 | originalObjectPropertySet.forEach(elem -> extendedOntology.addObjectProperty(elem));  | 
            ||
| 289 | originalClassSet.forEach(elem -> extendedOntology.addClass(elem));  | 
            ||
| 290 | return extendedOntology;  | 
            ||
| 291 | }  | 
            ||
| 292 | |||
| 293 | /**  | 
            ||
| 294 | * Returns the class graph.  | 
            ||
| 295 | *  | 
            ||
| 296 | * @return the class graph.  | 
            ||
| 297 | */  | 
            ||
| 298 | 	protected IntegerSubsumerGraph getClassGraph() { | 
            ||
| 299 | return this.status.getClassGraph();  | 
            ||
| 300 | }  | 
            ||
| 301 | |||
| 302 | @Override  | 
            ||
| 303 | 	public IntegerHierarchicalGraph getClassHierarchy() { | 
            ||
| 304 | 		if (!isReady()) { | 
            ||
| 305 | throw new UnclassifiedOntologyException();  | 
            ||
| 306 | }  | 
            ||
| 307 | return this.classHierarchy;  | 
            ||
| 308 | }  | 
            ||
| 309 | |||
| 310 | /**  | 
            ||
| 311 | * Returns information about how the processor configuration.  | 
            ||
| 312 | *  | 
            ||
| 313 | * @return information about how the processor configuration  | 
            ||
| 314 | */  | 
            ||
| 315 | 	public List<Map.Entry<String, String>> getConfigurationInfo() { | 
            ||
| 316 | List<Map.Entry<String, String>> ret = new ArrayList<>();  | 
            ||
| 317 | 		ret.add(createEntry("processor", getClass().getSimpleName())); | 
            ||
| 318 | 		ret.add(createEntry("iterations per log entry", "" + loggingFrequency)); | 
            ||
| 319 | 		ret.add(createEntry("classes read (including TOP and BOTTOM classes)", | 
            ||
| 320 | "" + getEntityManager().getEntities(IntegerEntityType.CLASS, false).size()));  | 
            ||
| 321 | 		ret.add(createEntry("object properties read (including TOP and BOTTOM object properties)", | 
            ||
| 322 | "" + getEntityManager().getEntities(IntegerEntityType.OBJECT_PROPERTY, false).size()));  | 
            ||
| 323 | 		ret.add(createEntry("auxiliary classes created (including nominals)", | 
            ||
| 324 | "" + getEntityManager().getEntities(IntegerEntityType.CLASS, true).size()));  | 
            ||
| 325 | 		ret.add(createEntry("auxiliary classes created for nominals", "" + getEntityManager().getIndividuals().size())); | 
            ||
| 326 | 		ret.add(createEntry("auxiliary object properties created", | 
            ||
| 327 | "" + getEntityManager().getEntities(IntegerEntityType.OBJECT_PROPERTY, true).size()));  | 
            ||
| 328 | 		ret.add(createEntry("chain S", this.chainS.toString())); | 
            ||
| 329 | 		ret.add(createEntry("chain R", this.chainR.toString())); | 
            ||
| 330 | return ret;  | 
            ||
| 331 | }  | 
            ||
| 332 | |||
| 333 | @Override  | 
            ||
| 334 | 	public IntegerHierarchicalGraph getDataPropertyHierarchy() throws UnclassifiedOntologyException { | 
            ||
| 335 | 		if (!isReady()) { | 
            ||
| 336 | throw new UnclassifiedOntologyException();  | 
            ||
| 337 | }  | 
            ||
| 338 | return this.dataPropertyHierarchy;  | 
            ||
| 339 | }  | 
            ||
| 340 | |||
| 341 | /**  | 
            ||
| 342 | * Computes the descendants using only a hierarchical graph.  | 
            ||
| 343 | *  | 
            ||
| 344 | * @param hierarchicalGraph  | 
            ||
| 345 | * a hierarchical graph containing parents and children  | 
            ||
| 346 | * @param vertex  | 
            ||
| 347 | * starting vertex to compute the descendants  | 
            ||
| 348 | * @return the descendants according the graph  | 
            ||
| 349 | */  | 
            ||
| 350 | View Code Duplication | 	private Set<Integer> getDescendants(IntegerHierarchicalGraph hierarchicalGraph, Integer vertex) { | 
            |
| 351 | Set<Integer> visited = new HashSet<>();  | 
            ||
| 352 | Set<Integer> queue = new HashSet<>();  | 
            ||
| 353 | queue.add(vertex);  | 
            ||
| 354 | 		while (!queue.isEmpty()) { | 
            ||
| 355 | Integer elem = queue.iterator().next();  | 
            ||
| 356 | queue.remove(elem);  | 
            ||
| 357 | visited.add(elem);  | 
            ||
| 358 | Set<Integer> children = new HashSet<>();  | 
            ||
| 359 | children.addAll(hierarchicalGraph.getChildren(elem));  | 
            ||
| 360 | children.removeAll(visited);  | 
            ||
| 361 | queue.addAll(children);  | 
            ||
| 362 | }  | 
            ||
| 363 | return visited;  | 
            ||
| 364 | }  | 
            ||
| 365 | |||
| 366 | @Override  | 
            ||
| 367 | 	public Map<Integer, Set<Integer>> getDirectTypes() { | 
            ||
| 368 | 		if (!isReady()) { | 
            ||
| 369 | throw new UnclassifiedOntologyException();  | 
            ||
| 370 | }  | 
            ||
| 371 | return Collections.unmodifiableMap(this.directTypes.asMap());  | 
            ||
| 372 | }  | 
            ||
| 373 | |||
| 374 | 	protected IntegerEntityManager getEntityManager() { | 
            ||
| 375 | return this.entityManager;  | 
            ||
| 376 | }  | 
            ||
| 377 | |||
| 378 | 	protected IntegerSubsumerGraph getObjectPropertyGraph() { | 
            ||
| 379 | return this.status.getObjectPropertyGraph();  | 
            ||
| 380 | }  | 
            ||
| 381 | |||
| 382 | @Override  | 
            ||
| 383 | 	public IntegerHierarchicalGraph getObjectPropertyHierarchy() { | 
            ||
| 384 | 		if (!isReady()) { | 
            ||
| 385 | throw new UnclassifiedOntologyException();  | 
            ||
| 386 | }  | 
            ||
| 387 | return this.objectPropertyHierarchy;  | 
            ||
| 388 | }  | 
            ||
| 389 | |||
| 390 | /**  | 
            ||
| 391 | * Returns the ontology object factory.  | 
            ||
| 392 | *  | 
            ||
| 393 | * @return the ontology object factory.  | 
            ||
| 394 | */  | 
            ||
| 395 | 	public NormalizedIntegerAxiomFactory getOntologyObjectFactory() { | 
            ||
| 396 | return this.factory;  | 
            ||
| 397 | }  | 
            ||
| 398 | |||
| 399 | /**  | 
            ||
| 400 | * Returns the binary relation for a given id, or and empty relation if the  | 
            ||
| 401 | * id is unknown.  | 
            ||
| 402 | *  | 
            ||
| 403 | * @param relationId  | 
            ||
| 404 | * relation id  | 
            ||
| 405 | * @return the binary relation for the given id, or an empty relation if no  | 
            ||
| 406 | * relation is already defined  | 
            ||
| 407 | */  | 
            ||
| 408 | 	protected IntegerBinaryRelation getRelation(Integer relationId) { | 
            ||
| 409 | Objects.requireNonNull(relationId);  | 
            ||
| 410 | return this.status.getRelationSet().get(relationId);  | 
            ||
| 411 | }  | 
            ||
| 412 | |||
| 413 | /**  | 
            ||
| 414 | * Returns a set containing all relation ids.  | 
            ||
| 415 | *  | 
            ||
| 416 | * @return the set of all relation ids  | 
            ||
| 417 | */  | 
            ||
| 418 | 	protected Set<Integer> getRelationIdSet() { | 
            ||
| 419 | return Collections.unmodifiableSet(this.status.getRelationSet().getElements());  | 
            ||
| 420 | }  | 
            ||
| 421 | |||
| 422 | @Override  | 
            ||
| 423 | 	public Map<Integer, Set<Integer>> getSameIndividualMap() { | 
            ||
| 424 | 		if (!isReady()) { | 
            ||
| 425 | throw new UnclassifiedOntologyException();  | 
            ||
| 426 | }  | 
            ||
| 427 | return Collections.unmodifiableMap(this.sameIndividualMap.asMap());  | 
            ||
| 428 | }  | 
            ||
| 429 | |||
| 430 | /**  | 
            ||
| 431 | * Returns information about the processor status.  | 
            ||
| 432 | *  | 
            ||
| 433 | * @return information about the processor status.  | 
            ||
| 434 | */  | 
            ||
| 435 | 	public List<Map.Entry<String, String>> getStatusInfo() { | 
            ||
| 436 | List<Map.Entry<String, String>> ret = new ArrayList<>();  | 
            ||
| 437 | 		ret.add(createEntry("iteration", "" + this.iteration)); | 
            ||
| 438 | 		ret.add(createEntry("Q_S", "" + this.status.getNumberOfSEntries())); | 
            ||
| 439 | 		ret.add(createEntry("Q_R", "" + this.status.getNumberOfREntries())); | 
            ||
| 440 | 		ret.add(createEntry("S", "" + this.status.getDeepSizeOfS())); | 
            ||
| 441 | 		ret.add(createEntry("R", "" + this.status.getDeepSizeOfR())); | 
            ||
| 442 | 		ret.add(createEntry("V", "" + this.status.getSizeOfV())); | 
            ||
| 443 | 		ret.add(createEntry("subV", "" + this.status.getDeepSizeOfV())); | 
            ||
| 444 | return ret;  | 
            ||
| 445 | }  | 
            ||
| 446 | |||
| 447 | @Override  | 
            ||
| 448 | 	public boolean isReady() { | 
            ||
| 449 | return this.isReady;  | 
            ||
| 450 | }  | 
            ||
| 451 | |||
| 452 | /**  | 
            ||
| 453 | * Post processes the data after the classification phase.  | 
            ||
| 454 | */  | 
            ||
| 455 | 	protected void postProcess() { | 
            ||
| 456 | removeAuxiliaryObjectProperties();  | 
            ||
| 457 | this.objectPropertyHierarchy = new IntegerHierarchicalGraphImpl(getObjectPropertyGraph());  | 
            ||
| 458 | |||
| 459 | removeAuxiliaryClassesExceptNominals();  | 
            ||
| 460 | IntegerHierarchicalGraph hierarchicalGraph = new IntegerHierarchicalGraphImpl(this.status.getClassGraph());  | 
            ||
| 461 | processNominals(hierarchicalGraph);  | 
            ||
| 462 | this.directTypes = computeDirectTypes(hierarchicalGraph);  | 
            ||
| 463 | this.sameIndividualMap = computeSameIndividualMap(hierarchicalGraph);  | 
            ||
| 464 | |||
| 465 | removeAuxiliaryNominals();  | 
            ||
| 466 | this.classHierarchy = new IntegerHierarchicalGraphImpl(this.status.getClassGraph());  | 
            ||
| 467 | };  | 
            ||
| 468 | |||
| 469 | /**  | 
            ||
| 470 | * The configuration follows the following steps:  | 
            ||
| 471 | * <ul>  | 
            ||
| 472 | * <li>creates the property hierarchy</li>  | 
            ||
| 473 | * <li>prepares all the queues to run the algorithm</li>  | 
            ||
| 474 | * </ul>  | 
            ||
| 475 | *  | 
            ||
| 476 | * @param ontology  | 
            ||
| 477 | * ontology  | 
            ||
| 478 | */  | 
            ||
| 479 | 	protected void preProcess(ExtendedOntology ontology) { | 
            ||
| 480 | 		logger.fine("configuring processor ..."); | 
            ||
| 481 | |||
| 482 | this.isReady = false;  | 
            ||
| 483 | this.status = new ClassifierStatusImpl(getEntityManager(), ontology);  | 
            ||
| 484 | this.dataPropertyHierarchy = new IntegerHierarchicalGraphImpl(new IntegerSubsumerGraphImpl(  | 
            ||
| 485 | IntegerEntityManager.bottomDataPropertyId, IntegerEntityManager.topDataPropertyId));  | 
            ||
| 486 | Set<Integer> classNameSet = new HashSet<>();  | 
            ||
| 487 | classNameSet.addAll(this.status.getExtendedOntology().getClassSet());  | 
            ||
| 488 | 		classNameSet.forEach(className -> { | 
            ||
| 489 | this.status.addNewSEntry(className, className);  | 
            ||
| 490 | this.status.addNewSEntry(className, topClassId);  | 
            ||
| 491 | });  | 
            ||
| 492 | |||
| 493 | 		logger.fine("processor configured."); | 
            ||
| 494 | logger.fine(showConfigurationInfo());  | 
            ||
| 495 | |||
| 496 | int numberOfCores = Runtime.getRuntime().availableProcessors();  | 
            ||
| 497 | 		logger.fine("number of cores : " + numberOfCores); | 
            ||
| 498 | |||
| 499 | // uncomment the following two lines to allow multithreaded mode  | 
            ||
| 500 | // int suggestedNumberOfThreads = (numberOfCores / 2) - 1;  | 
            ||
| 501 | // this.multiThreadedMode = suggestedNumberOfThreads >= 4;  | 
            ||
| 502 | |||
| 503 | 		if (this.multiThreadedMode) { | 
            ||
| 504 | 			logger.fine("running processor on multiple threads."); | 
            ||
| 505 | 		} else { | 
            ||
| 506 | 			logger.fine("running processor on a single thread."); | 
            ||
| 507 | }  | 
            ||
| 508 | }  | 
            ||
| 509 | |||
| 510 | @Override  | 
            ||
| 511 | 	public boolean process() { | 
            ||
| 512 | boolean ret = false;  | 
            ||
| 513 | 		if (this.multiThreadedMode) { | 
            ||
| 514 | ret = processMultiThreaded();  | 
            ||
| 515 | 		} else { | 
            ||
| 516 | ret = processSingleThreaded();  | 
            ||
| 517 | }  | 
            ||
| 518 | 		if (ret) { | 
            ||
| 519 | 			if (this.loggingCount < 1) { | 
            ||
| 520 | this.loggingCount = loggingFrequency;  | 
            ||
| 521 | logger.fine(showStatusInfo());  | 
            ||
| 522 | }  | 
            ||
| 523 | }  | 
            ||
| 524 | return ret;  | 
            ||
| 525 | };  | 
            ||
| 526 | |||
| 527 | 	private boolean processMultiThreaded() { | 
            ||
| 528 | 		if (!this.isReady) { | 
            ||
| 529 | if (Objects.nonNull(this.threadS1) && Objects.nonNull(this.threadS2) && Objects.nonNull(this.threadR1)  | 
            ||
| 530 | && Objects.nonNull(this.threadR2) && this.threadS1.getState().equals(Thread.State.TERMINATED)  | 
            ||
| 531 | && this.threadS2.getState().equals(Thread.State.TERMINATED)  | 
            ||
| 532 | && this.threadR1.getState().equals(Thread.State.TERMINATED)  | 
            ||
| 533 | && this.threadR2.getState().equals(Thread.State.TERMINATED)  | 
            ||
| 534 | 					&& (this.status.getNumberOfSEntries() == 0) && (this.status.getNumberOfREntries() == 0)) { | 
            ||
| 535 | |||
| 536 | logger.fine(showStatusInfo());  | 
            ||
| 537 | postProcess();  | 
            ||
| 538 | logger.fine(showConfigurationInfo());  | 
            ||
| 539 | this.isReady = true;  | 
            ||
| 540 | 			} else { | 
            ||
| 541 | |||
| 542 | if ((Objects.isNull(this.threadS1)) || (Objects.nonNull(this.threadS1)  | 
            ||
| 543 | 						&& this.threadS1.getState().equals(Thread.State.TERMINATED))) { | 
            ||
| 544 | this.threadS1 = new WorkerThreadS();  | 
            ||
| 545 | this.threadS1.start();  | 
            ||
| 546 | 					logger.finest("starting new thread S-1 ..."); | 
            ||
| 547 | }  | 
            ||
| 548 | |||
| 549 | if ((Objects.isNull(this.threadS2)) || (Objects.nonNull(this.threadS2)  | 
            ||
| 550 | 						&& this.threadS2.getState().equals(Thread.State.TERMINATED))) { | 
            ||
| 551 | this.threadS2 = new WorkerThreadS();  | 
            ||
| 552 | this.threadS2.start();  | 
            ||
| 553 | 					logger.finest("starting new thread S-2 ..."); | 
            ||
| 554 | }  | 
            ||
| 555 | |||
| 556 | if ((Objects.isNull(this.threadR1)) || (Objects.nonNull(this.threadR1)  | 
            ||
| 557 | 						&& this.threadR1.getState().equals(Thread.State.TERMINATED))) { | 
            ||
| 558 | this.threadR1 = new WorkerThreadR();  | 
            ||
| 559 | this.threadR1.start();  | 
            ||
| 560 | 					logger.finest("starting new thread R-1 ..."); | 
            ||
| 561 | }  | 
            ||
| 562 | |||
| 563 | if ((Objects.isNull(this.threadR2)) || (Objects.nonNull(this.threadR2)  | 
            ||
| 564 | 						&& this.threadR2.getState().equals(Thread.State.TERMINATED))) { | 
            ||
| 565 | this.threadR2 = new WorkerThreadR();  | 
            ||
| 566 | this.threadR2.start();  | 
            ||
| 567 | 					logger.finest("starting new thread R-2 ..."); | 
            ||
| 568 | }  | 
            ||
| 569 | |||
| 570 | 				try { | 
            ||
| 571 | 					if (this.status.getNumberOfREntries() < this.status.getNumberOfSEntries()) { | 
            ||
| 572 | 						if ((this.iteration % 2) == 0) { | 
            ||
| 573 | this.threadR1.join();  | 
            ||
| 574 | 						} else { | 
            ||
| 575 | this.threadR2.join();  | 
            ||
| 576 | }  | 
            ||
| 577 | 					} else { | 
            ||
| 578 | 						if ((this.iteration % 2) == 0) { | 
            ||
| 579 | this.threadS1.join();  | 
            ||
| 580 | 						} else { | 
            ||
| 581 | this.threadS2.join();  | 
            ||
| 582 | }  | 
            ||
| 583 | }  | 
            ||
| 584 | 				} catch (InterruptedException e) { | 
            ||
| 585 | throw new IllegalStateException(e);  | 
            ||
| 586 | }  | 
            ||
| 587 | }  | 
            ||
| 588 | }  | 
            ||
| 589 | return !this.isReady;  | 
            ||
| 590 | }  | 
            ||
| 591 | |||
| 592 | /**  | 
            ||
| 593 | * Processes the nominals after the execution of the classification  | 
            ||
| 594 | * algorithm. It requires a hierarchical graph to get the descendants.  | 
            ||
| 595 | *  | 
            ||
| 596 | * @param hierarchicalGraph  | 
            ||
| 597 | * the hierarchical graph  | 
            ||
| 598 | */  | 
            ||
| 599 | 	private void processNominals(IntegerHierarchicalGraph hierarchicalGraph) { | 
            ||
| 600 | OptMap<Integer, Set<Integer>> reachabilityCache = new OptMapImpl<>(new HashMap<>());  | 
            ||
| 601 | Set<Integer> nominals = getEntityManager().getAuxiliaryNominals();  | 
            ||
| 602 | 		nominals.forEach(indiv -> { | 
            ||
| 603 | Set<Integer> descendants = getDescendants(hierarchicalGraph, indiv);  | 
            ||
| 604 | 			descendants.forEach(c -> { | 
            ||
| 605 | 				descendants.forEach(d -> { | 
            ||
| 606 | Collection<Integer> sC = getClassGraph().getSubsumers(c);  | 
            ||
| 607 | Collection<Integer> sD = getClassGraph().getSubsumers(d);  | 
            ||
| 608 | 					if (!(sD.containsAll(sC))) { | 
            ||
| 609 | 						if (computeReachability(c, reachabilityCache).contains(d)) { | 
            ||
| 610 | sD.forEach(elem -> this.status.getClassGraph().addAncestor(c, elem));  | 
            ||
| 611 | }  | 
            ||
| 612 | 						nominals.forEach(nominal -> { | 
            ||
| 613 | 							if (computeReachability(nominal, reachabilityCache).contains(d)) { | 
            ||
| 614 | sD.forEach(elem -> this.status.getClassGraph().addAncestor(c, elem));  | 
            ||
| 615 | }  | 
            ||
| 616 | });  | 
            ||
| 617 | }  | 
            ||
| 618 | });  | 
            ||
| 619 | });  | 
            ||
| 620 | });  | 
            ||
| 621 | }  | 
            ||
| 622 | |||
| 623 | 	private boolean processREntries() { | 
            ||
| 624 | boolean ret = false;  | 
            ||
| 625 | REntry entry = null;  | 
            ||
| 626 | 		try { | 
            ||
| 627 | entry = this.status.removeNextREntry();  | 
            ||
| 628 | 		} catch (NoSuchElementException e) { | 
            ||
| 629 | }  | 
            ||
| 630 | 		if (Objects.nonNull(entry)) { | 
            ||
| 631 | ret = true;  | 
            ||
| 632 | int property = entry.getProperty();  | 
            ||
| 633 | int leftClass = entry.getLeftClass();  | 
            ||
| 634 | int rightClass = entry.getRightClass();  | 
            ||
| 635 | boolean applied = this.status.addToR(property, leftClass, rightClass);  | 
            ||
| 636 | 			if (applied) { | 
            ||
| 637 | this.chainR.apply(this.status, property, leftClass, rightClass);  | 
            ||
| 638 | this.loggingCount--;  | 
            ||
| 639 | this.iteration++;  | 
            ||
| 640 | }  | 
            ||
| 641 | }  | 
            ||
| 642 | return ret;  | 
            ||
| 643 | }  | 
            ||
| 644 | |||
| 645 | 	private boolean processSEntries() { | 
            ||
| 646 | boolean ret = false;  | 
            ||
| 647 | SEntry entry = null;  | 
            ||
| 648 | 		try { | 
            ||
| 649 | entry = this.status.removeNextSEntry();  | 
            ||
| 650 | 		} catch (NoSuchElementException e) { | 
            ||
| 651 | }  | 
            ||
| 652 | 		if (Objects.nonNull(entry)) { | 
            ||
| 653 | ret = true;  | 
            ||
| 654 | int subClass = entry.getSubClass();  | 
            ||
| 655 | int superClass = entry.getSuperClass();  | 
            ||
| 656 | boolean applied = this.status.addToS(subClass, superClass);  | 
            ||
| 657 | 			if (applied) { | 
            ||
| 658 | this.chainS.apply(this.status, subClass, superClass);  | 
            ||
| 659 | this.loggingCount--;  | 
            ||
| 660 | this.iteration++;  | 
            ||
| 661 | }  | 
            ||
| 662 | }  | 
            ||
| 663 | return ret;  | 
            ||
| 664 | }  | 
            ||
| 665 | |||
| 666 | 	private boolean processSingleThreaded() { | 
            ||
| 667 | 		if (!this.isReady) { | 
            ||
| 668 | 			if ((this.status.getNumberOfSEntries() == 0) && (this.status.getNumberOfREntries() == 0)) { | 
            ||
| 669 | logger.fine(showStatusInfo());  | 
            ||
| 670 | postProcess();  | 
            ||
| 671 | logger.fine(showConfigurationInfo());  | 
            ||
| 672 | this.isReady = true;  | 
            ||
| 673 | 			} else { | 
            ||
| 674 | 				if (this.status.getNumberOfSEntries() > this.status.getNumberOfREntries()) { | 
            ||
| 675 | processSEntries();  | 
            ||
| 676 | 				} else { | 
            ||
| 677 | processREntries();  | 
            ||
| 678 | }  | 
            ||
| 679 | }  | 
            ||
| 680 | }  | 
            ||
| 681 | return !this.isReady;  | 
            ||
| 682 | }  | 
            ||
| 683 | |||
| 684 | 	private void removeAuxiliaryClassesExceptNominals() { | 
            ||
| 685 | Set<Integer> reqClasses = new HashSet<>();  | 
            ||
| 686 | 		getClassGraph().getElements().forEach(elem -> { | 
            ||
| 687 | 			if (!getEntityManager().isAuxiliary(elem)) { | 
            ||
| 688 | reqClasses.add(elem);  | 
            ||
| 689 | }  | 
            ||
| 690 | });  | 
            ||
| 691 | reqClasses.addAll(getEntityManager().getAuxiliaryNominals());  | 
            ||
| 692 | this.status.getClassGraph().retainAll(reqClasses);  | 
            ||
| 693 | }  | 
            ||
| 694 | |||
| 695 | 	private void removeAuxiliaryNominals() { | 
            ||
| 696 | Set<Integer> reqClasses = new HashSet<>();  | 
            ||
| 697 | reqClasses.addAll(getClassGraph().getElements());  | 
            ||
| 698 | reqClasses.removeAll(getEntityManager().getAuxiliaryNominals());  | 
            ||
| 699 | this.status.getClassGraph().retainAll(reqClasses);  | 
            ||
| 700 | }  | 
            ||
| 701 | |||
| 702 | /**  | 
            ||
| 703 | * This method removes the auxiliary object properties that were not  | 
            ||
| 704 | * generated as inverse of another one.  | 
            ||
| 705 | */  | 
            ||
| 706 | 	private void removeAuxiliaryObjectProperties() { | 
            ||
| 707 | Set<Integer> reqObjectProperties = new HashSet<>();  | 
            ||
| 708 | 		getObjectPropertyGraph().getElements().forEach(elem -> { | 
            ||
| 709 | 			if (!getEntityManager().isAuxiliary(elem)) { | 
            ||
| 710 | reqObjectProperties.add(elem);  | 
            ||
| 711 | }  | 
            ||
| 712 | });  | 
            ||
| 713 | this.status.getObjectPropertyGraph().retainAll(reqObjectProperties);  | 
            ||
| 714 | }  | 
            ||
| 715 | |||
| 716 | 	public String showConfigurationInfo() { | 
            ||
| 717 | StringBuffer sbuf = new StringBuffer();  | 
            ||
| 718 | 		getConfigurationInfo().forEach(entry -> { | 
            ||
| 719 | sbuf.append(entry.getKey());  | 
            ||
| 720 | 			sbuf.append(" = "); | 
            ||
| 721 | sbuf.append(entry.getValue());  | 
            ||
| 722 | 			sbuf.append("\n"); | 
            ||
| 723 | });  | 
            ||
| 724 | return sbuf.toString();  | 
            ||
| 725 | }  | 
            ||
| 726 | |||
| 727 | 	public String showStatusInfo() { | 
            ||
| 728 | StringBuffer sbuf = new StringBuffer();  | 
            ||
| 729 | 		getStatusInfo().forEach(entry -> { | 
            ||
| 730 | sbuf.append(entry.getKey());  | 
            ||
| 731 | 			sbuf.append("="); | 
            ||
| 732 | sbuf.append(entry.getValue());  | 
            ||
| 733 | 			sbuf.append(" "); | 
            ||
| 734 | });  | 
            ||
| 735 | return sbuf.toString();  | 
            ||
| 736 | }  | 
            ||
| 737 | |||
| 738 | 	public void outputSetS(Writer writer) throws IOException { | 
            ||
| 739 | this.status.outputSetS(writer);  | 
            ||
| 740 | }  | 
            ||
| 741 | |||
| 742 | 	public void outputSetR(Writer writer) throws IOException { | 
            ||
| 743 | this.status.outputSetR(writer);  | 
            ||
| 744 | }  | 
            ||
| 747 |