/*
* #!
* Ontopia Engine
* #-
* 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 net.ontopia.topicmaps.impl.tmapi2;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import net.ontopia.infoset.core.LocatorIF;
import net.ontopia.infoset.impl.basic.URILocator;
import net.ontopia.topicmaps.core.AssociationIF;
import net.ontopia.topicmaps.core.AssociationRoleIF;
import net.ontopia.topicmaps.core.OccurrenceIF;
import net.ontopia.topicmaps.core.TMObjectIF;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.core.TopicMapStoreIF;
import net.ontopia.topicmaps.core.TopicNameIF;
import net.ontopia.topicmaps.core.VariantNameIF;
import net.ontopia.topicmaps.impl.tmapi2.index.LiteralIndexImpl;
import net.ontopia.topicmaps.impl.tmapi2.index.NameIndex;
import net.ontopia.topicmaps.impl.tmapi2.index.ScopedIndexImpl;
import net.ontopia.topicmaps.impl.tmapi2.index.TypeInstanceIndexImpl;
import net.ontopia.topicmaps.utils.MergeUtils;
import org.tmapi.core.Association;
import org.tmapi.core.Locator;
import org.tmapi.core.Name;
import org.tmapi.core.Occurrence;
import org.tmapi.core.TMAPIRuntimeException;
import org.tmapi.core.Topic;
import org.tmapi.core.TopicMap;
import org.tmapi.core.Variant;
import org.tmapi.index.Index;
import org.tmapi.index.LiteralIndex;
import org.tmapi.index.ScopedIndex;
import org.tmapi.index.TypeInstanceIndex;
/**
* INTERNAL: OKS->TMAPI 2 object wrapper.
*/
public class TopicMapImpl extends ReifiableImpl implements TopicMap {
private TopicMapSystemIF tmsystem;
private TopicMapIF wrapped;
private TopicImpl defaultNameType = null;
// TMAPI indexes - lazy created when needed
private ScopedIndex scopedIndex = null;
private TypeInstanceIndex typeInstanceIndex = null;
private LiteralIndex literalIndex = null;
// the name index is for internal use and is definitely needed so we
// instantiate it right now
private NameIndex nameIndex = new NameIndex(this);
public TopicMapImpl(TopicMapSystemIF tmsystem, TopicMapStoreIF store) {
super(null);
this.tmsystem = tmsystem;
wrapped = store.getTopicMap();
topicMap = this;
}
TopicImpl getDefaultNameType() {
if (defaultNameType == null) {
String psi = net.ontopia.topicmaps.utils.PSI.SAM_NAMETYPE;
defaultNameType = createTopicBySubjectIdentifier(createLocator(psi));
}
return defaultNameType;
}
public Locator getLocator() {
return wrapLocator(wrapped.getStore().getBaseAddress());
}
/*
* (non-Javadoc)
*
* @see net.ontopia.topicmaps.impl.tmapi2.Construct#getWrapped()
*/
public TopicMapIF getWrapped() {
return wrapped;
}
public TopicNameIF unwrapName(Name name) {
return ((NameImpl) name).getWrapped();
}
public VariantNameIF unwrapVariant(Variant variant) {
return ((VariantImpl) variant).getWrapped();
}
public LocatorIF unwrapLocator(Locator loc) {
// other lcoators implementation should be supported to
if (loc instanceof LocatorImpl) {
return ((LocatorImpl) loc).getWrapped();
} else {
return URILocator.create(loc.toExternalForm());
}
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#close()
*/
public void close() {
wrapped.getStore().commit();
wrapped.getStore().close();
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#createAssociation(org.tmapi.core.Topic,
* org.tmapi.core.Topic[])
*/
public Association createAssociation(Topic type, Topic... scope) {
Check.typeNotNull(this, type);
Check.scopeNotNull(this, scope);
Check.scopeInTopicMap(this, scope);
Check.typeInTopicMap(this, type);
AssociationIF assoc = wrapped.getBuilder().makeAssociation(
unwrapTopic(type));
for (Topic theme : scope) {
assoc.addTheme(unwrapTopic(theme));
}
return wrapAssociation(assoc);
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#createAssociation(org.tmapi.core.Topic,
* java.util.Collection)
*/
public Association createAssociation(Topic type, Collection<Topic> scope) {
Check.scopeNotNull(this, scope);
return createAssociation(type, scope.toArray(new Topic[0]));
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#createLocator(java.lang.String)
*/
public Locator createLocator(String reference) {
return tmsystem.createLocator(reference);
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#createTopic()
*/
public TopicImpl createTopic() {
TopicImpl topic = wrapTopic(wrapped.getBuilder().makeTopic());
Locator itemIdentifier = createLocator("urn:x-ontopia" + System.currentTimeMillis()); // using time to hopefully get an unique locator
// check if we have a construct with the generated item identifier
while (getConstructByItemIdentifier(itemIdentifier)!=null) {
itemIdentifier = createLocator("urn:x-ontopia" + System.currentTimeMillis()); // using time to hopefully get an unique locator
}
topic.addItemIdentifier(itemIdentifier);
return topic;
}
/*
* (non-Javadoc)
*
* @see
* org.tmapi.core.TopicMap#createTopicByItemIdentifier(org.tmapi.core.Locator)
*/
public TopicImpl createTopicByItemIdentifier(Locator iid) {
Check.itemIdentifierNotNull(this, iid);
ConstructImpl tmc = getConstructByItemIdentifier(iid);
TopicImpl topic = null;
if (tmc != null && tmc instanceof TopicImpl) {
topic = (TopicImpl) tmc;
}
if (topic != null) {
return topic;
}
topic = getTopicBySubjectIdentifier(iid);
if (topic == null) {
topic = wrapTopic(wrapped.getBuilder().makeTopic());
}
topic.addItemIdentifier(iid);
return topic;
}
/*
* (non-Javadoc)
*
* @see
* org.tmapi.core.TopicMap#createTopicBySubjectIdentifier(org.tmapi.core.Locator
* )
*/
public TopicImpl createTopicBySubjectIdentifier(Locator sid) {
Check.itemIdentifierNotNull(this, sid);
TopicImpl topic = getTopicBySubjectIdentifier(sid);
if (topic != null) {
return topic;
}
ConstructImpl tmc = getConstructByItemIdentifier(sid);
if (tmc != null && tmc instanceof TopicImpl) {
topic = (TopicImpl) tmc;
}
if (topic == null) {
topic = wrapTopic(wrapped.getBuilder().makeTopic());
}
topic.addSubjectIdentifier(sid);
return topic;
}
/*
* (non-Javadoc)
*
* @see
* org.tmapi.core.TopicMap#createTopicBySubjectLocator(org.tmapi.core.Locator)
*/
public TopicImpl createTopicBySubjectLocator(Locator slo) {
Check.itemIdentifierNotNull(this, slo);
TopicImpl topic = getTopicBySubjectLocator(slo);
if (topic == null) {
topic = wrapTopic(wrapped.getBuilder().makeTopic());
topic.addSubjectLocator(slo);
}
return topic;
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#getAssociations()
*/
public Set<Association> getAssociations() {
return wrapSet(wrapped.getAssociations());
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#getConstructById(java.lang.String)
*/
public ConstructImpl getConstructById(String id) {
if (id == null) {
throw new IllegalArgumentException("The id must not be null");
}
return wrapTMObject(wrapped.getObjectById(id));
}
/*
* (non-Javadoc)
*
* @see
* org.tmapi.core.TopicMap#getConstructByItemIdentifier(org.tmapi.core.Locator
* )
*/
public ConstructImpl getConstructByItemIdentifier(Locator iid) {
if (iid == null) {
throw new IllegalArgumentException("The item identifier must not be null");
}
return wrapTMObject(wrapped.getObjectByItemIdentifier(unwrapLocator(iid)));
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#getIndex(java.lang.Class)
*/
@SuppressWarnings("unchecked")
public <I extends Index> I getIndex(Class<I> idx) {
if (idx == org.tmapi.index.ScopedIndex.class) {
if (scopedIndex == null)
scopedIndex = new ScopedIndexImpl(this);
return (I) scopedIndex;
}
if (idx == org.tmapi.index.TypeInstanceIndex.class) {
if (typeInstanceIndex == null)
typeInstanceIndex = new TypeInstanceIndexImpl(this);
return (I) typeInstanceIndex;
}
if (idx == org.tmapi.index.LiteralIndex.class) {
if (literalIndex == null)
literalIndex = new LiteralIndexImpl(this);
return (I) literalIndex;
}
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#getParent()
*/
public ConstructImpl getParent() {
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.tmapi.core.TopicMap#getTopicBySubjectIdentifier(org.tmapi.core.Locator)
*/
public TopicImpl getTopicBySubjectIdentifier(Locator sid) {
Check.subjectIdentifierNotNull(sid);
return wrapTopic(wrapped.getTopicBySubjectIdentifier(unwrapLocator(sid)));
}
/*
* (non-Javadoc)
*
* @see
* org.tmapi.core.TopicMap#getTopicBySubjectLocator(org.tmapi.core.Locator)
*/
public TopicImpl getTopicBySubjectLocator(Locator slo) {
Check.subjectLocatorNotNull(slo);
return wrapTopic(wrapped.getTopicBySubjectLocator(unwrapLocator(slo)));
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#getTopics()
*/
public Set<Topic> getTopics() {
return wrapSet(wrapped.getTopics());
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.TopicMap#mergeIn(org.tmapi.core.TopicMap)
*/
public void mergeIn(TopicMap tm) {
if (tm == null) {
throw new IllegalArgumentException("The topic map must not be null");
}
if (this.equals(tm)) {
return;
}
MergeUtils.mergeInto(wrapped, ((TopicMapImpl) tm).getWrapped());
}
/*
* (non-Javadoc)
*
* @see org.tmapi.core.Construct#remove()
*/
public void remove() {
wrapped.getStore().delete(true);
tmsystem.remove(wrapped.getStore().getBaseAddress());
}
/* ---- wrappers: topic */
public TopicImpl wrapTopic(TopicIF topic) {
return topic == null ? null : new TopicImpl(this, topic);
}
public TopicIF unwrapTopic(Topic topic) {
return topic == null ? null : ((TopicImpl) topic).getWrapped();
}
/* ---- wrappers: association */
public AssociationImpl wrapAssociation(AssociationIF association) {
return association == null ? null : new AssociationImpl(this, association);
}
/* ---- wrappers: role */
public RoleImpl wrapRole(AssociationRoleIF role) {
return role == null ? null : new RoleImpl(this, role);
}
/* ---- wrappers: topic map object */
public ConstructImpl wrapTMObject(TMObjectIF tmobject) {
if (tmobject == null) {
return null;
} else if (tmobject instanceof AssociationIF) {
return new AssociationImpl(this, (AssociationIF) tmobject);
} else if (tmobject instanceof AssociationRoleIF) {
return new RoleImpl(this, (AssociationRoleIF) tmobject);
} else if (tmobject instanceof TopicNameIF) {
return wrapName((TopicNameIF) tmobject);
} else if (tmobject instanceof OccurrenceIF) {
return new OccurrenceImpl(this, (OccurrenceIF) tmobject);
} else if (tmobject instanceof TopicIF) {
return new TopicImpl(this, (TopicIF) tmobject);
} else if (tmobject instanceof TopicMapIF) {
return this;
} else if (tmobject instanceof VariantNameIF) {
return wrapVariant((VariantNameIF) tmobject);
} else {
throw new TMAPIRuntimeException("Invalid topic map object type: "
+ tmobject);
}
}
/* ---- wrappers: set */
public <T> Set<T> wrapSet(Collection<?> coll) {
return new LazySet<T>(this, coll);
}
public Occurrence wrapOccurrence(OccurrenceIF occ) {
return new OccurrenceImpl(this, occ);
}
public NameImpl wrapName(TopicNameIF name) {
if (name == null)
return null;
NameImpl wrapper = nameIndex.getName(name);
if (wrapper == null) {
wrapper = new NameImpl(this, name);
nameIndex.addName((NameImpl) wrapper);
}
// need to update variant cache of wrapper
if (wrapper.getVariants().size() != name.getVariants().size()) {
wrapper.clearVariants();
Iterator<?> it = name.getVariants().iterator();
while (it.hasNext()) {
VariantNameIF v = (VariantNameIF) it.next();
wrapVariant(v);
}
}
return wrapper;
}
public Locator wrapLocator(LocatorIF loc) {
return tmsystem.wrapLocator(loc);
}
public VariantImpl wrapVariant(VariantNameIF variant) {
if (variant == null)
return null;
NameImpl name = nameIndex.getName(variant.getTopicName());
// if we don't have a wrapped name, we create one
if (name==null) {
name = wrapName(variant.getTopicName());
}
VariantImpl v = null;
for (Variant tmp : name.getVariants()) {
if (((VariantImpl)tmp).getWrapped().equals(variant)) {
v = (VariantImpl) tmp;
break;
}
}
if (v == null) {
v = new VariantImpl(this, name, variant);
name.addVariant(v);
}
return v;
}
}