/*
* #!
* Ontopia Navigator
* #-
* 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.nav2.utils;
import java.util.Iterator;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.core.TopicNameIF;
import net.ontopia.topicmaps.core.VariantNameIF;
import net.ontopia.topicmaps.entry.TopicMapReferenceIF;
import net.ontopia.topicmaps.utils.TopicStringifiers;
import net.ontopia.topicmaps.utils.NameGrabber;
import net.ontopia.topicmaps.utils.PSI;
import net.ontopia.utils.GrabberIF;
import net.ontopia.utils.StringifierIF;
import net.ontopia.utils.GrabberStringifier;
import net.ontopia.topicmaps.nav2.core.NavigatorPageIF;
import net.ontopia.topicmaps.nav2.core.NavigatorRuntimeException;
import net.ontopia.topicmaps.nav2.core.NavigatorConfigurationIF;
import net.ontopia.topicmaps.nav2.core.UserIF;
import net.ontopia.topicmaps.nav2.core.NavigatorPageIF;
import net.ontopia.topicmaps.nav2.impl.basic.CustomNameStringifier;
import net.ontopia.topicmaps.nav.context.UserFilterContextStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* INTERNAL: Utility class to provide easy access to a stringified
* representation of given topic map objects using the page context to
* make use of the user defined scope.
*/
public final class Stringificator {
// initialization of logging facility
private static Logger log = LoggerFactory
.getLogger(Stringificator.class.getName());
// default stringifier
private static final StringifierIF DEF_NAME_STRINGIFIER =
new CustomNameStringifier();
public static String toString(NavigatorPageIF context, Object elem)
throws NavigatorRuntimeException {
return toString(context, elem, null, null, null, null);
}
public static String toString(NavigatorPageIF context, Object elem,
String nameGrabberCN, String nameStringifierCN,
String basenameScopeVarName, String variantScopeVarName) throws NavigatorRuntimeException {
StringifierIF stringifier = null;
GrabberIF nameGrabber = null;
StringifierIF nameStringifier = null;
if (nameStringifierCN != null)
nameStringifier = (StringifierIF) context.getNavigatorApplication()
.getInstanceOf(nameStringifierCN);
else
nameStringifier = DEF_NAME_STRINGIFIER;
if (nameGrabberCN != null)
nameGrabber = (GrabberIF) context.getNavigatorApplication()
.getInstanceOf(nameGrabberCN);
// --- stringifier for topic
if (elem instanceof TopicIF) {
TopicMapIF topicmap = context.getTopicMap();
UserIF user = FrameworkUtils.getUser(context.getPageContext());
UserFilterContextStore filterContext = user.getFilterContext();
if ((filterContext == null ||
(filterContext.getScopeTopicNames(topicmap).isEmpty() &&
filterContext.getScopeVariantNames(topicmap).isEmpty())) &&
basenameScopeVarName == null &&
variantScopeVarName == null) {
// ie: if this is one of the 99% most common cases
stringifier = new FastStringifier(topicmap);
} else {
List basenameScope = new ArrayList();
List variantScope = new ArrayList();
// prepare-scope-1: add themes that are in user context filter
if (filterContext != null) {
if (topicmap == null)
// FIXME: shouldn't we really throw an exception instead?
log.warn("No topic map in context.");
else {
basenameScope.addAll(filterContext.getScopeTopicNames(topicmap));
variantScope.addAll(filterContext.getScopeVariantNames(topicmap));
}
}
// prepare-scope-2: add themes that are specified by attribute scope
if (basenameScopeVarName != null)
basenameScope.addAll(context.getContextManager().getValue(basenameScopeVarName));
if (variantScopeVarName != null)
variantScope.addAll(context.getContextManager().getValue(variantScopeVarName));
// Add display theme if exists (bug #670)
TopicIF display_theme = topicmap.getTopicBySubjectIdentifier(PSI.getXTMDisplay());
if (display_theme != null)
variantScope.add(display_theme);
// if name should be grabbed with the custom grabber
if (nameGrabber != null) {
// TODO: how to make use of the scope using the custom grabber
stringifier = new GrabberStringifier(nameGrabber,
nameStringifier);
}
else {
// name should be grabbed in accordance to scope
stringifier = new GrabberStringifier(new NameGrabber(basenameScope, variantScope, false),
nameStringifier);
}
}
}
// --- base name or variant
else if (elem instanceof TopicNameIF) {
if (nameGrabber != null)
stringifier = new GrabberStringifier(nameGrabber, nameStringifier);
else
stringifier = nameStringifier;
}
else if (elem instanceof VariantNameIF) {
if (nameGrabber != null)
stringifier = new GrabberStringifier(nameGrabber, nameStringifier);
else
stringifier = nameStringifier;
}
// --- TopicMapReferenceIF
else if (elem instanceof TopicMapReferenceIF) {
return ((TopicMapReferenceIF) elem).getTitle();
}
// --- String
else if (elem instanceof String) {
return (String) elem;
}
// --- otherwise signal error
else {
StringBuilder msg =
new StringBuilder("Expected collection which contains topics," +
" base names, variants or topic map refs as elements.\n");
if (elem != null)
msg.append("But got instance of class " +
elem.getClass().getName() + ". ");
else
msg.append("First element in input collection is null. ");
log.error(msg.toString());
throw new NavigatorRuntimeException(msg.toString());
}
// set custom strings to display for fail situations
if (stringifier instanceof CustomNameStringifier) {
NavigatorConfigurationIF navConf = context.getNavigatorApplication()
.getConfiguration();
String str = null;
// --- nonexistent
str = navConf.getProperty(NavigatorConfigurationIF.NAMESTRING_NONEXISTENT, null);
if (str != null)
((CustomNameStringifier) stringifier).setStringNonExistent(str);
// --- null value
str = navConf.getProperty(NavigatorConfigurationIF.NAMESTRING_NULLVALUE, null);
if (str != null)
((CustomNameStringifier) stringifier).setStringValueNull(str);
// --- empty value
str = navConf.getProperty(NavigatorConfigurationIF.NAMESTRING_EMPTYVALUE, null);
if (str != null)
((CustomNameStringifier) stringifier).setStringValueEmpty(str);
}
return stringifier.toString(elem);
}
// --- Fast stringifier (optimization for Nokia)
static class FastStringifier extends CustomNameStringifier {
private TopicMapIF topicmap;
private TopicIF vntheme;
private TopicIF defnametype;
public FastStringifier(TopicMapIF topicmap) {
this.topicmap = topicmap;
this.defnametype = topicmap.getTopicBySubjectIdentifier(PSI.getSAMNameType());
this.vntheme = topicmap.getTopicBySubjectIdentifier(PSI.getXTMDisplay());
}
protected String getValue(String value) {
if (value == null)
return stringValueNull;
else if (value.equals(""))
return stringValueEmpty;
else
return value;
}
public String toString(Object object) {
// 0: verify that we have a topic at all
if (object == null)
return stringNonExistent;
TopicIF topic = (TopicIF) object;
// 1: pick base name with the fewest topics in scope
TopicNameIF bn = null;
int bn_least = 0xEFFF;
Iterator it = topic.getTopicNames().iterator();
while (it.hasNext()) {
TopicNameIF candidate = (TopicNameIF) it.next();
int themes = candidate.getScope().size();
if (candidate.getType() == defnametype)
themes += Integer.MIN_VALUE; // prefer default name type
if (themes < bn_least) {
bn = candidate;
bn_least = themes;
}
}
if (bn == null)
return stringNonExistent;
// 2: if we have a vntheme, pick variant with fewest topics in scope
// beyond vntheme; penalty for no vntheme = 0xFF topics
if (vntheme == null)
return getValue(bn.getValue());
VariantNameIF vn = null;
int vn_least = 0xEFFF;
it = bn.getVariants().iterator();
while (it.hasNext()) {
VariantNameIF candidate = (VariantNameIF) it.next();
Collection scope = candidate.getScope();
int themes;
if (scope.contains(vntheme)) {
themes = scope.size() - 1;
if (themes < vn_least) {
vn = candidate;
vn_least = themes;
}
}
}
if (vn == null || vn.getValue() == null)
return getValue(bn.getValue());
return getValue(vn.getValue());
}
}
}