/**
* Copyright 2012 Universitat Pompeu Fabra.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package org.onexus.collection.store.sql;
import org.onexus.collection.api.utils.FieldLink;
import org.onexus.resource.api.ORI;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class LinksNetworkComparator implements Comparator<ORI> {
private ORI fromCollection;
private Map<ORI, List<FieldLink>> networkLinks;
public LinksNetworkComparator(Map<ORI, List<FieldLink>> networkLinks, ORI fromCollection) {
this.networkLinks = networkLinks;
this.fromCollection = fromCollection;
}
@Override
public int compare(ORI a, ORI b) {
int a_b = depend(a, b, 0, new HashSet<ORI>());
int b_a = depend(b, a, 0, new HashSet<ORI>());
if (a_b != -1 && b_a != -1) {
if (a_b == 0 && b_a == 0) {
List<FieldLink> linksA = networkLinks.get(a);
List<FieldLink> linksB = networkLinks.get(b);
if (linksA.size() > linksB.size()) {
removeLinksToOrFromCollection(linksA, b);
} else {
removeLinksToOrFromCollection(linksB, a);
}
return compare(a, b);
} else {
return Integer.valueOf(a_b).compareTo(Integer.valueOf(b_a));
}
}
if (a_b != -1) {
return 1;
}
if (b_a != -1) {
return -1;
}
return 0;
}
private void removeLinksToOrFromCollection(List<FieldLink> links, ORI collection) {
for (int i = 0; i < links.size(); i++) {
FieldLink link = links.get(i);
if (link.getFromCollection().equals(collection) || link.getToCollection().equals(collection)) {
links.set(i, null);
}
}
links.removeAll(Collections.singletonList(null));
}
/*
Check if collection a depends on b
Returns -1 if not depends, 0 if there is a direct dependency. Otherwise the depth of the dependency.
*/
private int depend(ORI a, ORI b, int depth, Set<ORI> visitedNodes) {
// End of the path, no dependency if we reach the fromCollection.
if (b.equals(fromCollection)) {
return -1;
}
// Break cycles
if (visitedNodes.contains(a)) {
return -1;
}
List<FieldLink> links = networkLinks.get(a);
if (links == null || links.isEmpty()) {
return -1;
}
// Check direct dependency
for (FieldLink link : links) {
if (link.getToCollection().equals(a) && link.getFromCollection().equals(b)) {
return depth;
}
if (link.getToCollection().equals(b) && link.getFromCollection().equals(a)) {
return depth;
}
}
visitedNodes.add(a);
// Check derived dependencies
int minDerived = -1;
for (FieldLink link : links) {
ORI nextCollection = link.getToCollection().equals(a) ? link.getFromCollection() : link.getToCollection();
int derived = depend(nextCollection, b, depth + 1, visitedNodes);
if (derived != -1 && (minDerived == -1 || derived < minDerived)) {
minDerived = derived;
}
}
return minDerived;
}
}