/* * Copyright 2016 Martynas Jusevičius <[email protected]>. * * 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 com.atomgraph.processor.util; import com.atomgraph.core.util.StateBuilder; import com.atomgraph.processor.exception.ParameterException; import com.atomgraph.processor.model.Template; import java.util.List; import java.util.Map.Entry; import java.util.Set; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriBuilder; import org.apache.jena.query.QuerySolutionMap; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.Property; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.Resource; import org.spinrdf.model.SPINFactory; import com.atomgraph.processor.model.Parameter; import com.atomgraph.processor.vocabulary.LDT; import com.sun.jersey.api.uri.UriComponent; import java.util.Iterator; import org.apache.jena.rdf.model.Statement; import org.apache.jena.rdf.model.StmtIterator; import org.apache.jena.vocabulary.RDF; import org.spinrdf.vocabulary.SPL; /** * * @author Martynas Jusevičius {@literal <[email protected]>} */ public class TemplateCall extends com.atomgraph.core.util.StateBuilder { private final Template template; private final Resource original; protected TemplateCall(Resource resource, Template template) { super(UriBuilder.fromUri(resource.getURI()), resource.getModel()); if (template == null) throw new IllegalArgumentException("Template cannot be null"); this.original = resource; this.template = template; } public static TemplateCall fromUri(String uri, Model model, Template template) { if (uri == null) throw new IllegalArgumentException("URI String cannot be null"); if (model == null) throw new IllegalArgumentException("Model cannot be null"); return new TemplateCall(model.createResource(uri), template); } public static TemplateCall fromResource(Resource resource, Template template) { return new TemplateCall(resource, template); } protected Resource getOriginal() { return original; } public final Template getTemplate() { // SPIN uses Template registry instead: // return SPINModuleRegistry.get().getTemplate(s.getResource().getURI(), getModel()); return template; } public String getURI() { return getResource().getURI(); } public TemplateCall applyArguments(MultivaluedMap<String, String> queryParams) { if (queryParams == null) throw new IllegalArgumentException("Query parameter map cannot be null"); // iterate parameters to find those that match query argument names Set<String> paramNames = getTemplate().getParameterMap().keySet(); for (String paramName : paramNames) { Parameter param = getTemplate().getParameterMap().get(paramName); if (queryParams.containsKey(paramName)) { List<String> argValues = queryParams.get(paramName); for (String argValue : argValues) arg(param, RDFNodeFactory.createTyped(argValue, param.getValueType())); } } return this; } public TemplateCall applyDefaults() { Iterator<Parameter> paramIt = getTemplate().getParameters().values().iterator(); while (paramIt.hasNext()) { Parameter param = paramIt.next(); RDFNode defaultValue = param.getDefaultValue(); if (defaultValue != null && !hasArgument(param.getPredicate())) arg(param, defaultValue); } return this; } public StmtIterator listArguments() { return getResource().listProperties(LDT.arg); } public boolean hasArgument(Property predicate) { return getArgument(predicate) != null; } public Resource getArgument(Property predicate) // TO-DO: create model class Argument { if (predicate == null) throw new IllegalArgumentException("Property cannot be null"); StmtIterator it = getResource().listProperties(LDT.arg); try { while (it.hasNext()) { Statement stmt = it.next(); Resource arg = stmt.getObject().asResource(); if (arg.getProperty(SPL.predicate).getResource().equals(predicate)) return arg; } } finally { it.close(); } return null; } public boolean hasArgument(String varName, RDFNode object) { return getArgument(varName, object) != null; } public Resource getArgument(String varName, RDFNode object) { if (varName == null) throw new IllegalArgumentException("Var name String cannot be null"); if (object == null) throw new IllegalArgumentException("RDFNode cannot be null"); StmtIterator it = getResource().listProperties(LDT.arg); try { while (it.hasNext()) { Statement stmt = it.next(); Resource arg = stmt.getObject().asResource(); if (arg.getProperty(SPL.predicate).getResource().getLocalName().equals(varName) && arg.getProperty(RDF.value).getObject().equals(object)) return arg; } } finally { it.close(); } return null; } public Statement getArgumentProperty(Property predicate) { Resource arg = getArgument(predicate); if (arg != null) return arg.getRequiredProperty(RDF.value); return null; } public TemplateCall arg(Parameter param, RDFNode value) { if (param == null) throw new IllegalArgumentException("Parameter cannot be null"); if (value == null) throw new IllegalArgumentException("RDFNode cannot be null"); Resource arg = StateBuilder.fromUri(getOriginal().getURI(), getResource().getModel()). property(param.getPredicate(), value). build(); return arg(arg.addProperty(RDF.type, param). addLiteral(LDT.paramName, param.getPredicate().getLocalName()). addProperty(SPL.predicate, param.getPredicate()). addProperty(RDF.value, value)); } public TemplateCall arg(Resource arg) { if (arg == null) throw new IllegalArgumentException("Resource cannot be null"); getResource().addProperty(LDT.arg, arg); String paramName = arg.getPropertyResourceValue(SPL.predicate).getLocalName(); RDFNode value = arg.getProperty(RDF.value).getObject(); String encodedValue = value.toString(); // not a reliable serialization // we URI-encode values ourselves because Jersey 1.x fails to do so: https://java.net/jira/browse/JERSEY-1717 if (value.isURIResource()) encodedValue = UriComponent.encode(value.asResource().getURI(), UriComponent.Type.UNRESERVED); if (value.isLiteral()) encodedValue = UriComponent.encode(value.asLiteral().getString(), UriComponent.Type.UNRESERVED); getUriBuilder().queryParam(paramName, encodedValue); return this; } public TemplateCall validateOptionals() { Set<Entry<Property, Parameter>> paramEntries = getTemplate().getParameters().entrySet(); for (Entry<Property, Parameter> entry : paramEntries) { if (!hasArgument(entry.getKey()) && !entry.getValue().isOptional()) throw new ParameterException(entry.getValue(), getTemplate()); } return this; } public QuerySolutionMap getQuerySolutionMap() { QuerySolutionMap qsm = new QuerySolutionMap(); org.spinrdf.model.TemplateCall spinTemplateCall = SPINFactory.asTemplateCall(getTemplate().getQuery()); if (spinTemplateCall != null) { qsm = spinTemplateCall.getInitialBinding(); List<org.spinrdf.model.Argument> spinArgs = spinTemplateCall.getTemplate().getArguments(false); // add SPIN Arguments that match LDT Arguments (by predicate) for (org.spinrdf.model.Argument spinArg : spinArgs) if (getTemplate().getParameters().containsKey(spinArg.getPredicate()) && hasArgument(spinArg.getPredicate())) { Parameter param = getTemplate().getParameters().get(spinArg.getPredicate()); qsm.add(param.getVarName(), getArgumentProperty(param.getPredicate()).getObject()); } } return qsm; } /* @Override public String toString() { return new StringBuilder(). append("[<"). append(build().getURI()). append(">"). append("[<"). append(getTemplate().getURI()). append(">"). append("]"). toString(); } */ }