/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.clerezza.platform.documentation.viewer;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.clerezza.jaxrs.utils.TrailingSlash;
import org.apache.clerezza.platform.documentation.DocumentationProvider;
import org.apache.clerezza.rdf.core.BNode;
import org.apache.clerezza.rdf.core.Graph;
import org.apache.clerezza.rdf.core.LiteralFactory;
import org.apache.clerezza.rdf.core.MGraph;
import org.apache.clerezza.rdf.core.Triple;
import org.apache.clerezza.rdf.core.UriRef;
import org.apache.clerezza.rdf.core.access.TcManager;
import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl;
import org.apache.clerezza.rdf.core.impl.SimpleMGraph;
import org.apache.clerezza.rdf.core.impl.TripleImpl;
import org.apache.clerezza.rdf.ontologies.DISCOBITS;
import org.apache.clerezza.rdf.ontologies.RDF;
import org.apache.clerezza.rdf.ontologies.DOCUMENTATION;
import org.apache.clerezza.rdf.utils.GraphNode;
import org.apache.clerezza.rdf.utils.UnionMGraph;
/**
*
* The documentation viewer provides a webpage that shows the available
* documentation.
*
* @scr.component
* @scr.service interface="java.lang.Object"
* @scr.property name="javax.ws.rs" type="Boolean" value="true"
*
* @author mir
*/
@Path("/documentation")
public class DocumentationViewer {
/**
* @scr.reference
*/
private TcManager tcManager;
/**
* Redirects to the overview page
*
* @return {@link Response}
*
*/
@GET
public GraphNode documentationPage(@Context UriInfo uriInfo) {
TrailingSlash.enforcePresent(uriInfo);
Graph documentations = tcManager.getGraph(
DocumentationProvider.DOCUMENTATION_GRAPH_URI);
Collection<DocumentationItem> docItems = getDocItems(documentations);
List<DocumentationItem> sortedDocItems = sortDocItems(docItems);
MGraph mGraph = new SimpleMGraph();
BNode orderedContent = createOrderedContent(sortedDocItems, mGraph);
BNode titledContent = createTitledContent(orderedContent, mGraph);
MGraph resultGraph = new UnionMGraph(mGraph, documentations);
GraphNode resultNode = new GraphNode(titledContent, resultGraph);
return resultNode;
}
private Collection<DocumentationItem> getDocItems(Graph documentations) {
Iterator<Triple> docs = documentations.filter(null,
DOCUMENTATION.documentation, null);
Map<UriRef,DocumentationItem> uri2docItemObj =
new HashMap<UriRef,DocumentationItem>();
while (docs.hasNext()) {
Triple docc = docs.next();
UriRef docItem = (UriRef) docc.getObject();
Iterator<Triple> afterDocItemsIter = documentations.filter(docItem,
DOCUMENTATION.after, null);
Set<UriRef> afterDocItems = new HashSet<UriRef>();
while (afterDocItemsIter.hasNext()) {
afterDocItems.add((UriRef) afterDocItemsIter.next().getObject());
}
DocumentationItem docItemObj = new DocumentationItem(
docItem, afterDocItems, uri2docItemObj);
uri2docItemObj.put(docItem, docItemObj);
}
return uri2docItemObj.values();
}
protected List<DocumentationItem> sortDocItems(
Collection<DocumentationItem> docItems) {
List<DocumentationItem> result =
new ArrayList<DocumentationItem>();
Iterator<DocumentationItem> items = docItems.iterator();
OUTER: while (items.hasNext()) {
DocumentationItem item = items.next();
for (int i = 0; i < result.size(); i++ ) {
if (result.get(i).isAfer(item.documentationItem)) {
result.add(i, item);
continue OUTER;
}
}
result.add(item);
}
return result;
}
private BNode createOrderedContent(List<DocumentationItem> sortedDocItems,
MGraph mGraph) {
BNode orderedContent = new BNode();
mGraph.add(new TripleImpl(orderedContent, RDF.type, DISCOBITS.OrderedContent));
Integer pos = 0;
Iterator<DocumentationItem> docItemObjsIter = sortedDocItems.iterator();
while (docItemObjsIter.hasNext()) {
DocumentationItem docItemObj = docItemObjsIter.next();
BNode containedDoc = new BNode();
mGraph.add(new TripleImpl(orderedContent, DISCOBITS.contains,
containedDoc));
mGraph.add(new TripleImpl(containedDoc, DISCOBITS.pos,
new PlainLiteralImpl(pos.toString())));
mGraph.add(new TripleImpl(containedDoc, DISCOBITS.holds,
docItemObj.documentationItem));
pos++;
}
return orderedContent;
}
private BNode createTitledContent(BNode orderedContent, MGraph mGraph) {
BNode titledContent = new BNode();
mGraph.add(new TripleImpl(titledContent, RDF.type, DISCOBITS.TitledContent));
BNode title = new BNode();
mGraph.add(new TripleImpl(title, DISCOBITS.pos, new PlainLiteralImpl("0")));
BNode titleXml = new BNode();
mGraph.add(new TripleImpl(titleXml, RDF.type, DISCOBITS.XHTMLInfoDiscoBit));
mGraph.add(new TripleImpl(titleXml, DISCOBITS.infoBit,
LiteralFactory.getInstance().createTypedLiteral("Documentation")));
mGraph.add(new TripleImpl(title, DISCOBITS.holds, titleXml));
mGraph.add(new TripleImpl(title, RDF.type, DISCOBITS.Entry));
mGraph.add(new TripleImpl(titledContent, DISCOBITS.contains, title));
BNode content = new BNode();
mGraph.add(new TripleImpl(content, DISCOBITS.pos, new PlainLiteralImpl("1")));
mGraph.add(new TripleImpl(content, DISCOBITS.holds, orderedContent));
mGraph.add(new TripleImpl(content, RDF.type, DISCOBITS.Entry));
mGraph.add(new TripleImpl(titledContent, DISCOBITS.contains, content));
return titledContent;
}
protected static class DocumentationItem {
private UriRef documentationItem;
private Set<UriRef> afterDocItems;
private boolean transitiveAfterDocItemsAdded = false;
private Map<UriRef, DocumentationItem> uri2docItemObj;
DocumentationItem(UriRef doumentationItem, Set<UriRef> explicitAfterDocItems,
Map<UriRef, DocumentationItem> uri2docItemObj) {
this.documentationItem = doumentationItem;
this.afterDocItems = explicitAfterDocItems;
this.uri2docItemObj = uri2docItemObj;
}
public boolean isAfer(UriRef docItem) {
return getAfterDocItems().contains(docItem);
}
private Set<UriRef> getAfterDocItems() {
Stack<DocumentationItem> stack = new Stack<DocumentationItem>();
stack.add(this);
return getAfterDocItems(stack);
}
private Set<UriRef> getAfterDocItems(Stack<DocumentationItem> stack) {
if (!transitiveAfterDocItemsAdded) {
Iterator<UriRef> afterDocUrisIter = afterDocItems.iterator();
while (afterDocUrisIter.hasNext()) {
UriRef uriRef = afterDocUrisIter.next();
DocumentationItem docItem = uri2docItemObj.get(uriRef);
if (stack.contains(docItem)) {
throw new RuntimeException("Documentation: cycle detected!\n"
+ stack.toString());
}
stack.add(docItem);
afterDocItems.addAll(docItem.getAfterDocItems(stack));
}
transitiveAfterDocItemsAdded = true;
}
return afterDocItems;
}
@Override
public String toString() {
StringWriter writer = new StringWriter();
writer.append("[");
writer.append(documentationItem.getUnicodeString());
writer.append(" is after (");
Iterator<UriRef> afterDocs = afterDocItems.iterator();
while (afterDocs.hasNext()) {
UriRef uriRef = afterDocs.next();
writer.append(uriRef.getUnicodeString());
if (afterDocs.hasNext()) {
writer.append(",");
}
}
writer.append(")]");
return writer.toString();
}
}
}