/*
* #!
* Ontopia OSL Schema
* #-
* Copyright (C) 2001 - 2014 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.schema.utils;
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
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.TopicNameIF;
import net.ontopia.topicmaps.schema.core.ConstraintIF;
import net.ontopia.topicmaps.schema.core.SchemaViolationException;
import net.ontopia.topicmaps.schema.core.TMObjectMatcherIF;
import net.ontopia.topicmaps.schema.core.ValidationHandlerIF;
import net.ontopia.topicmaps.schema.impl.osl.AnyTopicMatcher;
import net.ontopia.topicmaps.schema.impl.osl.AssociationRoleConstraint;
import net.ontopia.topicmaps.schema.impl.osl.InternalTopicRefMatcher;
import net.ontopia.topicmaps.schema.impl.osl.OccurrenceConstraint;
import net.ontopia.topicmaps.schema.impl.osl.ScopeSpecification;
import net.ontopia.topicmaps.schema.impl.osl.ScopedConstraintIF;
import net.ontopia.topicmaps.schema.impl.osl.SourceLocatorMatcher;
import net.ontopia.topicmaps.schema.impl.osl.SubjectIndicatorMatcher;
import net.ontopia.topicmaps.schema.impl.osl.TopicNameConstraint;
import net.ontopia.topicmaps.schema.impl.osl.TopicRoleConstraint;
import net.ontopia.topicmaps.schema.impl.osl.TypeSpecification;
import net.ontopia.topicmaps.schema.impl.osl.TypedConstraintIF;
import net.ontopia.utils.StringifierIF;
import net.ontopia.utils.OntopiaRuntimeException;
import net.ontopia.topicmaps.utils.TopicStringifiers;
/**
* INTERNAL: Validation handler that writes error reports (using some
* HTML markup) on each violation out to the given Writer.
*/
public class HTMLValidationHandler implements ValidationHandlerIF {
protected Writer out;
protected int errors;
protected StringifierIF stringifier;
public HTMLValidationHandler(Writer out) {
this.out = out;
this.errors = 0;
this.stringifier = TopicStringifiers.getDefaultStringifier();
}
public void startValidation() {
}
public void violation(String message, TMObjectIF container, Object offender,
ConstraintIF constraint)
throws SchemaViolationException {
try {
errors++;
out.write("<p><b>" + message + "</b>\n");
out.write("<blockquote>\n");
out.write("<table>\n");
if (offender instanceof AssociationRoleIF) {
AssociationRoleIF role = (AssociationRoleIF) offender;
out.write(printAssociationRole(role));
out.write("<tr><th>Association type</th><td>" +
printTopic(role.getAssociation().getType()) + "</td></tr>\n");
} else if (offender instanceof AssociationIF) {
AssociationIF assoc = (AssociationIF) offender;
out.write("<tr><th>Association type</th><td>" +
printTopic(assoc.getType()) + "</td></tr>\n");
} else if (offender instanceof TopicNameIF) {
TopicNameIF bn = (TopicNameIF) offender;
out.write("<tr><th>Base name</th><td>'" + bn.getValue() +
"'</td></tr>\n");
printScope(bn.getScope());
out.write("<tr><th>Topic</th><td>" + printTopic(bn.getTopic()) +
"</td></tr>\n");
} else if (offender instanceof OccurrenceIF) {
OccurrenceIF occ = (OccurrenceIF) offender;
out.write("<tr><th>Occurrence</th><td>" + occ + "</td></tr>\n");
out.write("<tr><th>Type</th><td>" + printTopic(occ.getType()) +
"</td></tr>\n");
printScope(occ.getScope());
out.write("<tr><th>Topic</th><td>" + printTopic(occ.getTopic()) +
"</td></tr>\n");
} else if (offender == null && constraint != null) {
out.write("<tr><th>Constraint</th><td>" + printConstraint(constraint) +
"</td></tr>\n");
if (container instanceof TopicIF)
out.write("<tr><th>Topic</th><td>"+ printTopic((TopicIF) container) +
"</td></tr>\n");
if (container instanceof AssociationIF) {
AssociationIF assoc = (AssociationIF) container;
out.write("<tr><th>Association type</th><td>"+ printTopic(assoc.getType()) +
"</td></tr>\n");
Iterator it = assoc.getRoles().iterator();
while (it.hasNext()) {
AssociationRoleIF role = (AssociationRoleIF) it.next();
out.write(printAssociationRole(role));
}
}
} else {
if (container instanceof TopicIF)
out.write("<tr><th>Owner</th><td>" + printTopic((TopicIF)container) + "</td></tr>\n");
else
out.write("<tr><th>Owner</th><td>" + container + "</td></tr>\n");
if (offender instanceof TopicIF)
out.write("<tr><th>Object</th><td>" + printTopic((TopicIF) offender) +
"</td></tr>\n");
else
out.write("<tr><th>Object</th><td>" + offender + "</td></tr>\n");
}
out.write("</table>\n");
out.write("</blockquote>\n");
}
catch (java.io.IOException e) {
throw new OntopiaRuntimeException(e);
}
}
public void endValidation() {
}
// --- Internal methods
protected void printScope(Collection scope) throws java.io.IOException {
out.write("<tr><th>Scope</th><td>");
Iterator it = scope.iterator();
while(it.hasNext()) {
out.write(printTopic((TopicIF)it.next()));
if (it.hasNext()) out.write(", ");
}
out.write("</td></tr>\n");
}
protected String printTypes(TopicIF topic) {
StringBuilder buf = new StringBuilder();
Iterator it = topic.getTypes().iterator();
while (it.hasNext()) {
buf.append(printTopic((TopicIF) it.next()));
if (it.hasNext())
buf.append(", ");
}
return buf.toString();
}
protected String printTopic(TopicIF topic) {
if (topic == null)
return "[null]";
String name = stringifier.toString(topic);
if (name.equals("[No name]"))
return topic.toString();
else
return name;
}
protected String printConstraint(ConstraintIF constraint) {
if (constraint instanceof TopicRoleConstraint)
return "Topic role constraint, role type: " +
printTypeSpec(((TypedConstraintIF) constraint).getTypeSpecification()) +
", association types: " +
printTypeSpecs(((TopicRoleConstraint) constraint).getAssociationTypes());
else if (constraint instanceof AssociationRoleConstraint)
return "Association role constraint, role type: " +
printTypeSpec(((TypedConstraintIF) constraint).getTypeSpecification());
else if (constraint instanceof OccurrenceConstraint)
return "Occurrence constraint, type: " +
printTypeSpec(((TypedConstraintIF) constraint).getTypeSpecification());
else if (constraint instanceof TopicNameConstraint)
return "Base name constraint, scope: " +
printScopeSpec(((ScopedConstraintIF) constraint).getScopeSpecification());
else
return "[unknown]";
}
protected String printMatcher(TMObjectMatcherIF matcher) {
if (matcher instanceof SubjectIndicatorMatcher)
return "subject indicator " + ((SubjectIndicatorMatcher) matcher).getLocator().getAddress();
else if (matcher instanceof SourceLocatorMatcher)
return "source locator " + ((SourceLocatorMatcher) matcher).getLocator().getAddress();
else if (matcher instanceof InternalTopicRefMatcher)
return "<span title=\"relative source locator\">" + ((InternalTopicRefMatcher) matcher).getRelativeURI() + "</span>";
else if (matcher instanceof AnyTopicMatcher)
return "any";
else
return "[unknown]";
}
protected String printTypeSpecs(Collection specs) {
StringBuilder buf = new StringBuilder();
Iterator it = specs.iterator();
while (it.hasNext()) {
buf.append(printTypeSpec((TypeSpecification) it.next()));
if (it.hasNext())
buf.append(", ");
}
return buf.toString();
}
protected String printTypeSpec(TypeSpecification typespec) {
return printMatcher(typespec.getClassMatcher());
}
protected String printScopeSpec(ScopeSpecification scopespec) {
StringBuilder buf = new StringBuilder();
Iterator it = scopespec.getThemeMatchers().iterator();
if (!it.hasNext())
return "[unconstrained]";
while (it.hasNext()) {
buf.append(printMatcher((TMObjectMatcherIF) it.next()));
if (it.hasNext())
buf.append(", ");
}
return buf.toString();
}
protected String printAssociationRole(AssociationRoleIF role) {
StringBuilder buf = new StringBuilder();
buf.append("<tr><th>Association role player</th><td>" +
printTopic(role.getPlayer()) + "</td></tr>\n");
buf.append("<tr><th>Association role type</th><td>" +
printTopic(role.getType()) + "</td></tr>\n");
return buf.toString();
}
// ---
public int getErrors() {
return errors;
}
}