/*
* #!
* Ontopoly Editor
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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 ontopoly.conversion;
import gnu.trove.map.hash.TObjectIntHashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import net.ontopia.infoset.core.LocatorIF;
import net.ontopia.topicmaps.core.AssociationIF;
import net.ontopia.topicmaps.core.AssociationRoleIF;
import net.ontopia.topicmaps.core.OccurrenceIF;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicNameIF;
/**
* INTERNAL: Utility class that tracks ontological information. This
* class is used by the ConvertTopicMap action as part of the ontopoly
* schema inferencing code.
*/
public class SchemaTracker {
protected static final Collection<TopicIF> NULL_COLLECTION = Collections.singleton(null);
protected Map<TopicIF,TopicType> ttypes = new HashMap<TopicIF,TopicType>(); // ttype : { TopicType }
protected Map<TopicIF,Map<TopicIF,Map<TopicIF,PlayerType>>> atypes = new HashMap<TopicIF,Map<TopicIF,Map<TopicIF,PlayerType>>>(); // atypes : { rtypes : { ptypes : PlayerType } }
protected Collection<TopicIF> non_symmetric_atypes = new HashSet<TopicIF>();
protected Collection<TopicIF> utypedp = new HashSet<TopicIF>(); // untyped players
protected Collection<TopicIF> utypedt = new HashSet<TopicIF>(); // untyped topics
protected Map<TopicIF,Collection<TopicIF>> nscopes = new HashMap<TopicIF,Collection<TopicIF>>(); // nscope : [ ttypes ]
private class TopicType {
protected int count;
protected IdentityType subloc = new IdentityType();
protected IdentityType subind = new IdentityType();
protected Map<TopicIF,CharType> ntypes = new HashMap<TopicIF,CharType>(); // ntype : CharType
protected Map<TopicIF,CharType> oitypes = new HashMap<TopicIF,CharType>(); // otype : CharType
protected Map<TopicIF,CharType> oetypes = new HashMap<TopicIF,CharType>(); // otype : CharType
}
private abstract class AbstractProperty {
protected int count;
protected int mincard = -1;
protected int maxcard = -1;
void registerCardinality(int cardinality) {
this.count += cardinality;
if (cardinality > maxcard || maxcard == -1)
this.maxcard = cardinality;
if (cardinality < mincard || mincard == -1)
this.mincard = cardinality;
}
}
private class CharType extends AbstractProperty {
protected TopicIF type;
}
private class IdentityType extends AbstractProperty {
}
private class PlayerType extends AbstractProperty {
// protected TopicIF atype;
// protected TopicIF rtype;
// protected TopicIF ptype;
}
public void trackTopics(Collection<TopicIF> topics) {
Iterator<TopicIF> iter = topics.iterator();
while (iter.hasNext()) {
trackTopic(iter.next());
}
}
public void trackTopic(TopicIF topic) {
// topic types
Collection<TopicIF> types = topic.getTypes();
if (types.isEmpty()) {
types = NULL_COLLECTION;
utypedt.add(topic);
}
Iterator<TopicIF> titer = types.iterator();
while (titer.hasNext()) {
TopicIF ttype = titer.next();
TopicType ttinfo = createTopicType(ttype);
ttinfo.count++;
// subject locators
Collection<LocatorIF> sublocs = topic.getSubjectLocators();
ttinfo.subloc.registerCardinality(sublocs.size());
// subject indicators
Collection<LocatorIF> subinds = topic.getSubjectIdentifiers();
ttinfo.subind.registerCardinality(subinds.size());
// names
TObjectIntHashMap<TopicIF> ncards = new TObjectIntHashMap<TopicIF>();
Iterator<TopicNameIF> niter = topic.getTopicNames().iterator();
while (niter.hasNext()) {
TopicNameIF tn = niter.next();
// translate name scopes into name types
if (tn.getType() == null) {
Collection<TopicIF> scope = tn.getScope();
if (scope.size() == 1) {
Iterator<TopicIF> siter = scope.iterator();
while (siter.hasNext()) {
TopicIF theme = siter.next();
Collection<TopicIF> nstypes = nscopes.get(theme);
if (nstypes == null) {
nstypes = new HashSet<TopicIF>();
nscopes.put(theme, nstypes);
}
nstypes.add(ttype);
}
}
}
// name types
CharType ctype = createCharType(ttinfo.ntypes, tn.getType());
ctype.count++;
// track cardinalities
if (ncards.containsKey(ctype.type))
ncards.increment(ctype.type);
else
ncards.put(ctype.type, 1);
}
// register cardinalities
Iterator<CharType> ntiter = ttinfo.ntypes.values().iterator();
while (ntiter.hasNext()) {
CharType ct = ntiter.next();
ct.registerCardinality(ncards.get(ct.type));
}
// occurrences
TObjectIntHashMap<TopicIF> oicards = new TObjectIntHashMap<TopicIF>();
TObjectIntHashMap<TopicIF> oecards = new TObjectIntHashMap<TopicIF>();
Iterator<OccurrenceIF> oiter = topic.getOccurrences().iterator();
while (oiter.hasNext()) {
OccurrenceIF oc = oiter.next();
// internal occurrences vs external occurrences
if (oc.getLocator() == null) {
CharType ctype = createCharType(ttinfo.oitypes, oc.getType());
ctype.count++;
// track cardinalities
if (oicards.containsKey(ctype.type))
oicards.increment(ctype.type);
else
oicards.put(ctype.type, 1);
} else {
CharType ctype = createCharType(ttinfo.oetypes, oc.getType());
ctype.count++;
// track cardinalities
if (oecards.containsKey(ctype.type))
oecards.increment(ctype.type);
else
oecards.put(ctype.type, 1);
}
}
// register cardinalities
Iterator<CharType> oititer = ttinfo.oitypes.values().iterator();
while (oititer.hasNext()) {
CharType ct = oititer.next();
ct.registerCardinality(oicards.get(ct.type));
}
Iterator<CharType> oetiter = ttinfo.oetypes.values().iterator();
while (oetiter.hasNext()) {
CharType ct = oetiter.next();
ct.registerCardinality(oecards.get(ct.type));
}
}
}
public void trackAssociations(Collection<AssociationIF> assocs) {
Iterator<AssociationIF> iter = assocs.iterator();
while (iter.hasNext()) {
trackAssociation(iter.next());
}
}
public void trackAssociation(AssociationIF assoc) {
TopicIF atype = assoc.getType();
Collection<AssociationRoleIF> roles = assoc.getRoles();
boolean symmetric = (roles.size() == 2);
TopicIF prev_rtype = null;
Iterator<AssociationRoleIF> riter = roles.iterator();
while (riter.hasNext()) {
AssociationRoleIF role = riter.next();
TopicIF rtype = role.getType();
TopicIF player = role.getPlayer();
// symmetric association?
if (symmetric) {
if (prev_rtype == null)
prev_rtype = rtype;
else if (rtype == null || !rtype.equals(prev_rtype))
symmetric = false;
}
if (player != null) {
Collection<TopicIF> ptypes = player.getTypes();
if (ptypes.isEmpty()) {
ptypes = NULL_COLLECTION;
utypedp.add(player);
}
// TODO: mincard not really perfectly calculated
int cardinality = getPlayerCardinality(atype, rtype, player);
Iterator<TopicIF> piter = ptypes.iterator();
while (piter.hasNext()) {
TopicIF ptype = piter.next();
PlayerType pinfo = createPlayerType(atypes, atype, rtype, ptype);
pinfo.registerCardinality(0); // mincard, see above
pinfo.registerCardinality(cardinality);
}
}
}
// non-symmetric association type
if (!symmetric)
non_symmetric_atypes.add(atype);
}
protected int getPlayerCardinality(TopicIF atype, TopicIF rtype, TopicIF player) {
int result = 0;
Iterator<AssociationRoleIF> iter = player.getRoles().iterator();
while (iter.hasNext()) {
AssociationRoleIF role = iter.next();
TopicIF _rtype = role.getType();
if (_rtype == null || !_rtype.equals(rtype)) continue;
AssociationIF assoc = role.getAssociation();
if (assoc == null) continue;
TopicIF _atype = assoc.getType();
if (_atype != null && _atype.equals(atype))
result++;
}
return result;
}
// --- getters
public Collection<TopicIF> getTopicTypes() {
return ttypes.keySet();
}
public int getTopicTypeInstances(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null)
return 0;
else
return tt.count;
}
public int getSubjectLocatorMinCardinality(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
return tt.subloc.mincard;
}
public int getSubjectLocatorMaxCardinality(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
return tt.subloc.maxcard;
}
public int getSubjectIndicatorMinCardinality(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
return tt.subind.mincard;
}
public int getSubjectIndicatorMaxCardinality(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
return tt.subind.maxcard;
}
public Collection<TopicIF> getUntypedTopics() {
return utypedt;
}
public Collection<TopicIF> getUntypedPlayers() {
return utypedp;
}
public Collection<TopicIF> getNameTypes(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return Collections.emptySet();
return tt.ntypes.keySet();
}
public int getNameTypeMinCardinality(TopicIF ttype, TopicIF ntype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
CharType ct = (CharType)tt.ntypes.get(ntype);
if (ct == null) return 0;
return ct.mincard;
}
public int getNameTypeMaxCardinality(TopicIF ttype, TopicIF ntype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
CharType ct = (CharType)tt.ntypes.get(ntype);
if (ct == null) return 0;
return ct.maxcard;
}
public Collection<TopicIF> getExternalOccurrenceTypes(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return Collections.emptySet();
return tt.oetypes.keySet();
}
public int getExternalOccurrenceTypeMinCardinality(TopicIF ttype, TopicIF otype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
CharType ct = (CharType)tt.oetypes.get(otype);
if (ct == null) return 0;
return ct.mincard;
}
public int getExternalOccurrenceTypeMaxCardinality(TopicIF ttype, TopicIF otype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
CharType ct = (CharType)tt.oetypes.get(otype);
if (ct == null) return 0;
return ct.maxcard;
}
public Collection<TopicIF> getInternalOccurrenceTypes(TopicIF ttype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return Collections.emptySet();
return tt.oitypes.keySet();
}
public int getInternalOccurrenceTypeMinCardinality(TopicIF ttype, TopicIF otype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
CharType ct = (CharType)tt.oitypes.get(otype);
if (ct == null) return 0;
return ct.mincard;
}
public int getInternalOccurrenceTypeMaxCardinality(TopicIF ttype, TopicIF otype) {
TopicType tt = getTopicType(ttype);
if (tt == null) return 0;
CharType ct = (CharType)tt.oitypes.get(otype);
if (ct == null) return 0;
return ct.maxcard;
}
public Collection<TopicIF> getAssociationTypes() {
return atypes.keySet();
}
public Collection<TopicIF> getRoleTypes(TopicIF atype) {
Map<TopicIF,Map<TopicIF,PlayerType>> rmap = atypes.get(atype);
if (rmap == null)
return Collections.emptySet();
else
return rmap.keySet();
}
public Collection<TopicIF> getPlayerTypes(TopicIF atype, TopicIF rtype) {
Map<TopicIF,Map<TopicIF,PlayerType>> rmap = atypes.get(atype);
if (rmap == null)
return Collections.emptySet();
Map<TopicIF,PlayerType> pmap = rmap.get(rtype);
if (pmap == null)
return Collections.emptySet();
else
return pmap.keySet();
}
public int getPlayerTypeMinCardinality(TopicIF atype, TopicIF rtype, TopicIF ptype) {
Map<TopicIF,Map<TopicIF,PlayerType>> rmap = atypes.get(atype);
if (rmap == null) return 0;
Map<TopicIF,PlayerType> pmap = rmap.get(rtype);
if (pmap == null) return 0;
PlayerType pt = pmap.get(ptype);
return (pt == null ? 0 : pt.mincard);
}
public int getPlayerTypeMaxCardinality(TopicIF atype, TopicIF rtype, TopicIF ptype) {
Map<TopicIF,Map<TopicIF,PlayerType>> rmap = atypes.get(atype);
if (rmap == null) return 0;
Map<TopicIF,PlayerType> pmap = rmap.get(rtype);
if (pmap == null) return 0;
PlayerType pt = pmap.get(ptype);
return (pt == null ? 0 : pt.maxcard);
}
public Collection<TopicIF> getOntologyTypes() {
Collection<TopicIF> onto_types = new HashSet<TopicIF>();
// topic types
Iterator<TopicIF> ttypes = getTopicTypes().iterator();
while (ttypes.hasNext()) {
TopicIF ttype = ttypes.next();
onto_types.add(ttype);
// name types
Iterator<TopicIF> ntypes = getNameTypes(ttype).iterator();
while (ntypes.hasNext()) {
TopicIF ntype = ntypes.next();
onto_types.add(ntype);
}
// external occurrence types
Iterator<TopicIF> oetypes = getExternalOccurrenceTypes(ttype).iterator();
while (oetypes.hasNext()) {
TopicIF oetype = oetypes.next();
onto_types.add(oetype);
}
// internal occurrence types
Iterator<TopicIF> oitypes = getInternalOccurrenceTypes(ttype).iterator();
while (oitypes.hasNext()) {
TopicIF oitype = oitypes.next();
onto_types.add(oitype);
}
}
// association types
Iterator<TopicIF> atypes = getAssociationTypes().iterator();
while (atypes.hasNext()) {
TopicIF atype = atypes.next();
onto_types.add(atype);
// role types
Iterator<TopicIF> rtypes = getRoleTypes(atype).iterator();
while (rtypes.hasNext()) {
TopicIF rtype = rtypes.next();
onto_types.add(rtype);
}
}
return onto_types;
}
public Collection<TopicIF> getSuspectNameScopes() {
return nscopes.keySet();
}
public Collection<TopicIF> getNameScopeTopicTypes(TopicIF ntheme) {
return nscopes.get(ntheme);
}
public boolean isSymmetricAssociationType(TopicIF atype) {
return !non_symmetric_atypes.contains(atype);
}
// --- setters
protected TopicType getTopicType(TopicIF ttype) {
return (TopicType)ttypes.get(ttype);
}
protected TopicType createTopicType(TopicIF ttype) {
TopicType t = (TopicType)ttypes.get(ttype);
if (t == null) {
t = new TopicType();
// t.type = ttype;
ttypes.put(ttype, t);
}
return t;
}
protected CharType getCharType(Map<TopicIF,CharType> cmap, TopicIF ctype) {
return cmap.get(ctype);
}
protected CharType createCharType(Map<TopicIF,CharType> cmap, TopicIF ctype) {
CharType t = cmap.get(ctype);
if (t == null) {
t = new CharType();
t.type = ctype;
cmap.put(ctype, t);
}
return t;
}
protected PlayerType getPlayerType(Map<TopicIF,Map<TopicIF,Map<TopicIF,PlayerType>>> amap, TopicIF atype, TopicIF rtype, TopicIF ptype) {
Map<TopicIF,Map<TopicIF,PlayerType>> rmap = amap.get(atype);
if (rmap == null) return null;
Map<TopicIF,PlayerType> pmap = rmap.get(rtype);
if (pmap == null) return null;
return pmap.get(ptype);
}
protected PlayerType createPlayerType(Map<TopicIF,Map<TopicIF,Map<TopicIF,PlayerType>>> amap, TopicIF atype, TopicIF rtype, TopicIF ptype) {
Map<TopicIF,Map<TopicIF,PlayerType>> rmap = amap.get(atype);
if (rmap == null) {
rmap = new HashMap<TopicIF,Map<TopicIF,PlayerType>>();
amap.put(atype, rmap);
}
Map<TopicIF,PlayerType> pmap = rmap.get(rtype);
if (pmap == null) {
pmap = new HashMap<TopicIF,PlayerType>();
rmap.put(rtype, pmap);
}
PlayerType t = pmap.get(ptype);
if (t == null) {
t = new PlayerType();
// t.atype = atype;
// t.rtype = rtype;
// t.ptype = ptype;
pmap.put(ptype, t);
}
return t;
}
}