net.ontopia.topicmaps.utils.tmprefs.TopicMapPreferences Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ontopia-tmprefs Show documentation
Show all versions of ontopia-tmprefs Show documentation
Ontopia TopicMapPreferences provides a java.util.prefs.Preferences implementation that
reads and writes Preferences from and to Topic Maps.
/*
* #!
* Ontopia TopicMapPreferences
* #-
* 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.utils.tmprefs;
import java.util.prefs.Preferences;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;
import java.io.IOException;
import net.ontopia.topicmaps.core.TopicMapBuilderIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.core.TopicMapStoreIF;
import net.ontopia.topicmaps.entry.TopicMapReferenceIF;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.AssociationIF;
import net.ontopia.topicmaps.core.AssociationRoleIF;
import net.ontopia.topicmaps.core.OccurrenceIF;
import net.ontopia.topicmaps.core.index.ClassInstanceIndexIF;
import net.ontopia.topicmaps.utils.TopicStringifiers;
import net.ontopia.topicmaps.impl.utils.TMRevitalizer;
import net.ontopia.topicmaps.utils.MergeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TopicMapPreferences extends AbstractPreferences {
private static final Logger logger = LoggerFactory.getLogger(TopicMapPreferences.class);
protected HashMap children = new HashMap();
protected HashMap properties = new HashMap();
protected final TopicMapPreferencesFactory factory;
protected TopicMapReferenceIF topicMapReference;
protected TopicIF topic;
private final boolean isUserNode;
private HashSet propertiesStored = new HashSet();
private HashSet propertiesAdded = new HashSet();
private HashSet propertiesModified = new HashSet();
private HashSet propertiesRemoved = new HashSet();
private enum PropertyStatus { NONE, ADDED, MODIFIED, REMOVED; }
private synchronized void handlePropertyStatusChange(String key, PropertyStatus newStatus) {
propertiesAdded.remove(key);
propertiesModified.remove(key);
propertiesRemoved.remove(key);
switch (newStatus) {
case ADDED: propertiesAdded.add(key); break;
case MODIFIED: propertiesModified.add(key); break;
case REMOVED: propertiesRemoved.add(key); break;
}
}
public static TopicMapPreferences createSystemRoot(TopicMapReferenceIF topicMapReference, TopicMapPreferencesFactory factory) {
return new TopicMapPreferences(false, topicMapReference, factory);
}
public static TopicMapPreferences createUserRoot(TopicMapReferenceIF topicMapReference, TopicMapPreferencesFactory factory) {
return new TopicMapPreferences(true, topicMapReference, factory);
}
// constructor to create root Preference, boolean argument determines wether systemRoot or userRoot is created
private TopicMapPreferences(boolean isUserNode, TopicMapReferenceIF topicMapReference, TopicMapPreferencesFactory factory) {
super(null, "");
this.isUserNode = isUserNode;
this.topicMapReference = topicMapReference;
this.factory = factory;
newNode = true;
try {
this.sync(); // load from topic map upon creation
} catch (BackingStoreException e) {
logger.error("BackingStoreException: ", e);
}
}
// constructor to create non-root Preference, with parent and name
private TopicMapPreferences(TopicMapPreferences parent, String name) {
super(parent, name);
this.isUserNode = parent.isUserNode;
this.topicMapReference = parent.topicMapReference;
this.factory = parent.factory;
newNode = true;
}
// --- AbstractPreferences abstract method implementations
@Override
public boolean isUserNode() {
return isUserNode;
}
public String getSpi(String key) {
return properties.get(key);
}
public void putSpi(String key, String value) {
properties.put(key, value);
handlePropertyStatusChange(key, propertiesStored.contains(key) ? PropertyStatus.MODIFIED : PropertyStatus.ADDED);
propertiesStored.add(key);
}
public void removeSpi(String key) {
properties.remove(key);
handlePropertyStatusChange(key, propertiesStored.contains(key) ? PropertyStatus.REMOVED : PropertyStatus.NONE);
propertiesStored.remove(key);
}
public TopicMapPreferences childSpi(String name) {
if (children.get(name) == null) {
children.put(name, new TopicMapPreferences(this, name));
}
return children.get(name);
}
public void removeNodeSpi() {
children.clear();
properties.clear();
((TopicMapPreferences) parent()).children.remove(this.name());
}
public String[] keysSpi() {
return properties.keySet().toArray(new String[properties.size()]);
}
public String[] childrenNamesSpi() {
return children.keySet().toArray(new String[children.size()]);
}
public synchronized void syncSpi() throws BackingStoreException {
flushSpi();
if (isRemoved()) {
return;
}
TopicMapStoreIF store = null;
try {
store = createStore(topicMapReference, true); // readonly, we're only loading here
TopicMapIF topicmap = store.getTopicMap();
for (TopicIF childTopic : fetchChildren(topicmap, topic)) {
String childName = TopicStringifiers.toString(childTopic);
TopicMapPreferences childNode = (TopicMapPreferences) this.node(childName);
if ((childNode.topic != null) && (!MergeUtils.shouldMerge(childNode.topic, childTopic))) {
// if there already is a topic connectied to this node, different then childTopic, merge them
logger.warn("Duplicate topics found, merging them into " + absolutePath() + "/" + childName);
mergeTopics(childNode.topic, childTopic);
} else {
childNode.topic = childTopic;
}
}
propertiesStored.clear();
for (OccurrenceIF property : fetchProperties(topicmap)) {
String propertyName = TopicStringifiers.toString(property.getType());
String propertyValue = property.getValue();
properties.put(propertyName, propertyValue);
propertiesStored.add(propertyName);
}
} finally {
if (store != null) {
store.close();
}
}
}
public synchronized void flushSpi() throws BackingStoreException {
logger.debug("Flushing " + this);
TopicMapStoreIF store = null;
try {
store = createStore(topicMapReference, false); // read-write
TopicMapIF topicmap = store.getTopicMap();
TopicMapPreferencesOntology.loadOntology(topicmap); // load ontology as it might not be present
if (isRemoved()) {
if (topic != null) {
logger.debug("Removing " + this);
removeTopic(topicmap, topic);
}
} else {
topic = fetchTopic(topicmap);
for (String key : propertiesAdded) {
logger.debug("Adding property '" + key + "' = '" + properties.get(key) + "'");
TopicIF propertyType = fetchPropertyType(key, topicmap);
topicmap.getBuilder().makeOccurrence(topic, propertyType, properties.get(key));
}
for (String key : propertiesModified) {
logger.debug("Modifying property '" + key + "' = '" + properties.get(key) + "'");
TopicIF propertyType = fetchPropertyType(key, topicmap);
for (OccurrenceIF occurrence : topic.getOccurrences()) {
if (propertyType.equals(occurrence.getType())) {
occurrence.setValue(properties.get(key));
}
}
}
for (String key : propertiesRemoved) {
logger.debug("Removing property '" + key + "'");
TopicIF propertyType = fetchPropertyType(key, topicmap);
OccurrenceIF[] occurrencesArray = topic.getOccurrences().toArray(new OccurrenceIF[0]);
for (int i = 0; i < occurrencesArray.length; i++) {
OccurrenceIF occurrence = occurrencesArray[i];
if (propertyType.equals(occurrence.getType())) {
occurrence.remove();
}
}
}
propertiesAdded.clear();
propertiesModified.clear();
propertiesRemoved.clear();
}
store.commit();
} finally {
if (store != null) {
store.close();
}
}
}
protected TopicMapStoreIF createStore(TopicMapReferenceIF topicMapReference, boolean readonly) throws BackingStoreException {
try {
return topicMapReference.createStore(readonly);
} catch (IOException e) {
throw new BackingStoreException(e);
}
}
protected Set fetchChildren(TopicMapIF topicmap, TopicIF topic) {
TopicIF parentChildType = TopicMapPreferencesOntology.PARENTCHILD.t(topicmap);
TopicIF parentType = TopicMapPreferencesOntology.PARENT.t(topicmap);
TopicIF childType = TopicMapPreferencesOntology.CHILD.t(topicmap);
TopicIF preferenceType = TopicMapPreferencesOntology.PREFERENCE.t(topicmap);
Set result = new HashSet();
for (AssociationRoleIF role1 : revitalize(topic, topicmap).getRolesByType(parentType, parentChildType)) {
for (AssociationRoleIF role2 : role1.getAssociation().getRolesByType(childType)) {
TopicIF child = role2.getPlayer();
if (child.getTypes().contains(preferenceType)) {
result.add(child);
}
}
}
return result;
}
protected Set fetchProperties(TopicMapIF topicmap) {
TopicIF preferencePropertyType = TopicMapPreferencesOntology.PREFERENCEPROPERTY.t(topicmap);
Set result = new HashSet();
for (OccurrenceIF property : revitalize(topic, topicmap).getOccurrences()) {
if (property.getType().getTypes().contains(preferencePropertyType)) {
result.add(property);
}
}
return result;
}
protected TopicIF fetchPropertyType(String key, TopicMapIF topicmap) {
TopicIF preferencePropertyType = TopicMapPreferencesOntology.PREFERENCEPROPERTY.t(topicmap);
// try to fetch existing propertyType from topic map
ClassInstanceIndexIF index = (ClassInstanceIndexIF) topicmap.getIndex(ClassInstanceIndexIF.class.getName());
for (TopicIF propertyType : index.getTopics(preferencePropertyType)) {
if (key.equals(TopicStringifiers.toString(propertyType))) {
return revitalize(propertyType, topicmap);
}
}
// propertyType not found in topic map, create it now
TopicMapBuilderIF builder = topicmap.getBuilder();
TopicIF propertyType = builder.makeTopic(preferencePropertyType);
builder.makeTopicName(propertyType, key);
return propertyType;
}
protected TopicIF fetchTopic(TopicMapIF topicmap) throws BackingStoreException {
return (topic != null)
? revitalize(topic, topicmap)
: (parent() != null)
? createTopic(topicmap)
: (isUserNode)
? factory.createUserRootTopic(topicmap)
: factory.createSystemRootTopic(topicmap);
}
protected TopicIF createTopic(TopicMapIF topicmap) throws BackingStoreException {
TopicIF preferenceType = TopicMapPreferencesOntology.PREFERENCE.t(topicmap);
TopicIF parentChildType = TopicMapPreferencesOntology.PARENTCHILD.t(topicmap);
TopicIF parentType = TopicMapPreferencesOntology.PARENT.t(topicmap);
TopicIF childType = TopicMapPreferencesOntology.CHILD.t(topicmap);
TopicMapBuilderIF builder = topicmap.getBuilder();
TopicIF topic = builder.makeTopic(preferenceType);
builder.makeTopicName(topic, this.name());
AssociationIF a = builder.makeAssociation(parentChildType, childType, topic);
TopicIF parentTopic = ((TopicMapPreferences) parent()).fetchTopic(topicmap);
builder.makeAssociationRole(a, parentType, parentTopic);
return topic;
}
protected void removeTopic(TopicMapIF topicmap, TopicIF topic) throws BackingStoreException {
// specs: "If this method is invoked on a node that has been removed with the removeNode() method,
// flushSpi() is invoked on this node, but not on others."
// so, first remove children, then topic itself
logger.debug("Removing topic " + TopicStringifiers.toString(topic));
for (TopicIF child : fetchChildren(topicmap, topic)) {
removeTopic(topicmap, child);
}
topic.remove();
}
protected void mergeTopics(TopicIF targetTopic, TopicIF sourceTopic) throws BackingStoreException {
TopicMapStoreIF store = null;
try {
store = createStore(topicMapReference, false);
TopicMapIF topicmap = store.getTopicMap();
TopicIF currentTopic = revitalize(targetTopic, topicmap);
TopicIF duplicateTopic = revitalize(sourceTopic, topicmap);
MergeUtils.mergeInto(currentTopic, duplicateTopic);
store.commit();
} finally {
if (store != null) {
store.close();
}
}
}
protected TopicIF revitalize(TopicIF topic, TopicMapIF topicmap) {
return (TopicIF) new TMRevitalizer(topicmap).revitalize(topic);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy