/*******************************************************************************
* Copyright 2014 Miami-Dade County
*
* 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 org.sharegov.cirm.rest;
import java.util.Set;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import static org.sharegov.cirm.OWL.*;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.sharegov.cirm.OWL;
import org.sharegov.cirm.Refs;
import mjson.Json;
@Path("ui")
@Produces("application/json")
public class UiService extends RestService
{
Json prepareEditor(Json editor)
{
editor.delAt("isEditorOf");
Json fieldsOrder = editor.at("hasFieldsOrdering");
if (fieldsOrder != null)
{
editor.delAt("hasFieldsOrdering");
Json expanded = Json.array();
for (int i = 0; i < fieldsOrder.asJsonList().size(); i++)
{
Json el = fieldsOrder.at(i);
Json newel = getField(el.at("iri").asString());
if (newel != null)
expanded.add(newel);
else
expanded.add(el);
}
editor.set("fieldSequence", expanded);
}
return editor;
}
public Json getForm(OWLDataProperty prop)
{
OWLIndividual ind = objectProperty(individual(prop.getIRI()), "hasEditor");
Json result = null;
if (ind != null)
result = prepareEditor(OWL.toJSON(ind));
else for (OWLDataRange range : prop.getRanges(ontologies()))//prop.getRanges(ontology()))
{
switch (range.asOWLDatatype().getBuiltInDatatype())
{
case XSD_BOOLEAN:
{
result = OWL.toJSON(individual("DefaultCheckBox"));
break;
}
case XSD_STRING:
default:
{
result = OWL.toJSON(individual("DefaultInputBox"));
}
}
}
if (result != null)
{
Json attributes = result.at("attributes", Json.object());
attributes.set("name", prop.getIRI().getFragment());
if (result.has("type"))
result.set("head", result.atDel("type"));
return annotate(prop, result);
}
else
return result;
}
public Json getForm(OWLObjectProperty prop)
{
OWLIndividual ind = objectProperty(individual(prop.getIRI()), "hasEditor");
Json result = null;
if (ind != null)
result = prepareEditor(OWL.toJSON(ind));
else for (OWLClassExpression range : prop.getRanges(ontologies())) //prop.getRanges(ontology()))
{
result = getForm(range);
if (result != null)
break;
}
if (result != null)
{
Json attributes = result.at("attributes", Json.object());
attributes.set("name", prop.getIRI().getFragment());
if (result.has("type"))
result.set("head", result.atDel("type"));
return annotate(prop, result);
}
else
return null;
}
public Json getForm(OWLClassExpression expr)
{
switch (expr.getClassExpressionType())
{
case OWL_CLASS:
return getForm((OWLClass)expr);
case OBJECT_ONE_OF:
return getForm((OWLObjectOneOf)expr);
default:
return null;
}
}
Json getForm(OWLObjectOneOf en)
{
Json result = Json.object();
result.set("head", "UIDropDown");
Json options = Json.array();
for (OWLIndividual ind : en.getIndividuals())
{
options.add(Json.object()
.set("value", ind.toStringID())
.set("label", ind.isNamed() ? getEntityLabel((OWLEntity)ind) : ind.toString()));
}
result.set("options", options);
return result;
}
public Json getForm(OWLClass cl)
{
Json result = null;
// First see if that class has already an associated editor.
OWLIndividual editor = objectProperty(individual(cl.getIRI()), "hasEditor");
if (editor != null)
{
return prepareEditor(OWL.toJSON(ontology(), editor));
// Json jsonEditor = prepareEditor(app.toJSON(ontology(), editor));
// result = Json.object().with(jsonEditor);
// return result;
}
for (OWLClassExpression expr : cl.getEquivalentClasses(ontologies())) //ontology()
{
result = getForm(expr);
if (result != null)
return result;
}
result = Json.object();
// Next, get all properties that have the class in their domain.
//Set<OWLProperty<?, ?>> properties = app.getClassProperties(ontologies(), owlClass(cl.getIRI()));
Set<OWLProperty> properties = (Set)OWL.getClassProperties(ontology(), owlClass(cl.getIRI()));
// The form will be simply a JSON array of editors, one for each property.
Json A = Json.array();
for (OWLProperty prop : properties)
{
Json el = null;
if (prop instanceof OWLDataProperty)
el = getForm((OWLDataProperty)prop);
else if (prop instanceof OWLObjectProperty)
el = getForm((OWLObjectProperty)prop);
if (el != null)
A.add(el);
}
result.set("fieldSet", A);
return result;
}
Json getField(String propertyName)
{
IRI iri = fullIri(propertyName);
OWLDataProperty asDataProp = dataProperty(iri);
if (ontology().getDataPropertiesInSignature(true).contains(asDataProp))
//if (ontology().getDataPropertiesInSignature().contains(asDataProp))
return getForm(asDataProp);
OWLObjectProperty asObjectProp = objectProperty(iri);
if (ontology().getObjectPropertiesInSignature(true).contains(asObjectProp))
//if (ontology().getObjectPropertiesInSignature().contains(asObjectProp))
return getForm(objectProperty(iri));
return null;
}
public Json makeActionButton(String label, String postback)
{
Json result = OWL.toJSON(individual("DefaultActionButton"))
.set("content", label)
.set("postTo", postback)
.set("attributes", Json.object().set("type", "button"));
if (result.has("type"))
result.set("head", result.atDel("type"));
return result;
}
@GET
@Path("/new/{classname}")
public String getForm(@PathParam("classname") String classname)
{
return getForm(owlClass(fullIri(classname, Refs.topOntologyIRI.resolve())))
.set("head", "UIForm").toString();
}
@GET
@Path("/editor")
public Json makeEditor(@QueryParam("individual") String individualParam)
{
IRI iri = fullIri(individualParam);
if (isBusinessObject(iri))
{
OWLClass type = businessObjectType(iri);
return getForm(type).set("head", "UIForm");
}
// TODO ...
return Json.object();
}
@GET
@Path("/propertyEditor")
public Json makePropertyEditor(@QueryParam("property") String propertyId)
{
OWLObjectProperty prop = objectProperty(propertyId);
Json result = getForm(prop);
// for (OWLClassExpression range : prop.getRanges(ontology()))
// if ((result = getForm(range)) != null)
// break;
if (result == null)
{
OWLDataProperty dprop = dataProperty(propertyId);
Json fieldForm = getForm(dprop);
Json A = Json.array();
if (fieldForm != null)
A.add(fieldForm);
result = Json.object().set("fieldSequence", A).set("isStructured", false);
}
else
{
if (!result.has("fieldSequence"))
{
Json A = Json.array().add(result);
result = Json.object().set("fieldSequence", A);
}
result.set("isStructured", result.at("fieldSequence").asJsonList().size() > 1);
}
result.set("head", "UIForm");
return result;
}
public Json findTemplate(IRI iri)
{
OWLObjectProperty isTemplateOf = objectProperty("isTemplateOf");
OWLReasoner reasoner = reasoner(ontology());
Set<OWLNamedIndividual> S = reasoner.getInstances(
has(isTemplateOf, individual(iri)), true).getFlattened();
if (!S.isEmpty())
return OWL.toJSON(S.iterator().next());
OWLClass cl = owlClass(iri);
for (OWLClassExpression expr : cl.getSuperClasses(ontology()))
{
if (! (expr instanceof OWLClass))
continue;
S = reasoner.getInstances(has(isTemplateOf,
individual(((OWLClass)expr).getIRI())), true).getFlattened();
if (!S.isEmpty())
return OWL.toJSON(S.iterator().next());
}
// If everything fails, we just return the generic template for 'Thing' or
// simple an empty string.
S = reasoner.getInstances(
has(isTemplateOf, individual(iri)), true).getFlattened();
if (!S.isEmpty())
return OWL.toJSON(S.iterator().next());
else
{
return Json.object().set("hasContents", "[Object]")
.set("type", "HtmlTemplate");
}
}
/**
* <p>
* Return a display template for an individual.
* </p>
* @param iriAsString The IRI of the individual. It could be a business object
* IRI, in which case the business ontology is loaded to get the full individual,
* or a generic IRI refering to an individual or a class in the main ontology.
* @return
*/
@GET
@Path("/template/{iri}")
@Produces("application/json")
public String getTemplate(@PathParam("iri") String iriAsString, @QueryParam("type") String typeName)
{
Json result = null;
IRI iri = null; // the IRI of the individual whose template we'll be searching for.
// First check if this points to a business object, just be the format of the IRI
// in which case we are looking for a template defined for the class of the object.
if (iriAsString.startsWith(Refs.boIriPrefix.resolve()))
{
String className = iriAsString.substring(Refs.boIriPrefix.resolve().length()).split("/")[1];
iri = OWL.fullIri(className);
}
else
iri = fullIri(iriAsString);
// If it's not a class IRI, we need to loop through all its declared classes
if (ontology().getAxioms(owlClass(iri)).isEmpty())
{
IRI typeIri = null;
if (typeName != null && typeName.length() > 0)
typeIri = fullIri(typeName);
else for (OWLClassExpression type : individual(iri).getTypes(ontology()))
if (type instanceof OWLClass) // && (result = findTemplate(((OWLClass)type).getIRI())) != null)
{
typeIri = ((OWLClass)type).getIRI();
break;
}
if (typeIri != null)
iri = typeIri;
}
result = findTemplate(iri);
return (result != null) ? result.toString() : "{}";
}
}