blob: a4719a3cf1df345167762165254c201b3fed1bb0 [file] [log] [blame]
/**
* 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.jena.fuseki.server;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import org.apache.jena.atlas.lib.IRILib;
import org.apache.jena.atlas.logging.Log;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.iri.IRI;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.riot.system.IRIResolver;
/**
* Operations are symbol to look up in the {@link OperationRegistry#operationToHandler} map. The name
* of an {@code Operation} is not related to the service name used to invoke the operation
* which is determined by the {@link Endpoint}.
*/
public class Operation {
private static String NS = FusekiVocab.NS;
/** Create/intern. Maps short name to operation. */
static private Map<Node, Operation> mgr = new HashMap<>();
static public Operation get(Node node) { return mgr.get(node); }
/** @deprecated Use {@link #alloc(Node, String, String)}. */
@Deprecated
static public Operation register(String shortName, String description) {
String x = IRILib.encodeUriPath(shortName);
return alloc("http://migration/"+x, shortName, description);
}
/**
* Create an Operation - this operation interns operations so there is only
* one object for each operation. It is an extensible enum.
*/
static public Operation alloc(String iriStr, String name, String description) {
IRI iri = IRIResolver.parseIRI(iriStr);
if ( iri.hasViolation(false) )
Log.warn(Operation.class, "Poor Operation name: "+iriStr+" : Not an IRI");
if ( iri.isRelative() )
Log.warn(Operation.class, "Poor Operation name: "+iriStr+" : Relative IRI");
Node node = NodeFactory.createURI(iriStr);
return alloc(node, name, description);
}
/**
* Create an Operation - this operation interns operations so there is only
* object for each operation. It is an extensible enum.
*/
static public Operation alloc(Node op, String name, String description) {
return mgr.computeIfAbsent(op, (x)->create(x, name, description));
}
/** Create; not registered */
static private Operation create(Node id, String shortName, String description) {
// Currently, (3.13.0) the JS name is the short display name in lower
// case. Just in case it diverges in the future, leave provision for
// a different setting.
return new Operation(id, shortName, shortName.toLowerCase(Locale.ROOT), description);
}
public static final Operation Query = alloc(FusekiVocab.opQuery.asNode(), "query", "SPARQL Query");
public static final Operation Update = alloc(FusekiVocab.opUpdate.asNode(), "update", "SPARQL Update");
public static final Operation Upload = alloc(FusekiVocab.opUpload.asNode(), "upload", "File Upload");
public static final Operation GSP_R = alloc(FusekiVocab.opGSP_r.asNode(), "gsp-r", "Graph Store Protocol (Read)");
public static final Operation GSP_RW = alloc(FusekiVocab.opGSP_rw.asNode(), "gsp-rw", "Graph Store Protocol");
public static final Operation NoOp = alloc(FusekiVocab.opNoOp.asNode(), "no-op", "No Op");
public static final Operation Shacl = alloc(FusekiVocab.opShacl.asNode(), "SHACL", "SHACL Validation");
static {
// Not everyone will remember "_" vs "-" so ...
altName(FusekiVocab.opNoOp_alt, FusekiVocab.opNoOp);
altName(FusekiVocab.opGSP_r_alt, FusekiVocab.opGSP_r);
altName(FusekiVocab.opGSP_rw_alt, FusekiVocab.opGSP_rw);
}
// -- Object
private final Node id;
private final String name;
// Name used in JSON in the "server" description and "stats" details.
// This name is know to the JS code (e.g. dataset.js).
private final String jsName;
private final String description;
private Operation(Node fullName, String name, String jsName, String description) {
this.id = fullName;
this.name = name;
// Currently, this
this.jsName = jsName;
this.description = description;
}
public Node getId() {
return id;
}
/** Return the display name for this operation. */
public String getName() {
return name;
}
/**
* Name used in JSON in the "server" description and "stats" details.
* Highlighted by JENA-1766.
* This name is know to the JS code.
*/
public String getJsonName() {
return jsName;
}
/** Return the description for this operation. */
public String getDescription() {
return description;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
// Could be this == obj
// because we intern'ed the object
@Override
public boolean equals(Object obj) {
if ( this == obj )
return true;
if ( !(obj instanceof Operation) )
return false;
Operation other = (Operation)obj;
return Objects.equals(id, other.id);
}
@Override
public String toString() {
return name;
}
private static void altName(Resource altName, Resource properName) {
altName(altName.asNode(), properName.asNode());
}
private static void altName(Node altName, Node properName) {
Operation op = mgr.get(properName);
mgr.put(altName, op);
}
}