org.apache.jena.ontapi.common.OntObjectPersonalityBuilder Maven / Gradle / Ivy
/*
* 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.ontapi.common;
import org.apache.jena.ontapi.model.OntClass;
import org.apache.jena.ontapi.model.OntEntity;
import org.apache.jena.ontapi.model.OntObject;
import org.apache.jena.enhanced.EnhGraph;
import org.apache.jena.enhanced.Implementation;
import org.apache.jena.enhanced.Personality;
import org.apache.jena.graph.Node;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* An {@link OntPersonality} builder.
* This must be the only place to create various {@code OntPersonality} objects.
*/
@SuppressWarnings("WeakerAccess")
public class OntObjectPersonalityBuilder {
private final Map, Function> extFactories = new HashMap<>();
private final Map, Implementation> stdFactories = new HashMap<>();
private String name;
private OntPersonality.Punnings punnings;
private OntPersonality.Builtins builtins;
private OntPersonality.Reserved reserved;
private OntConfig config;
/**
* Makes a full copy of the given {@link OntPersonality}
* in the form of modifiable {@link OntObjectPersonalityBuilder builder}.
*
* @param from {@link OntPersonality} to copy settings, not {@code null}
* @return {@link OntObjectPersonalityBuilder}
*/
public static OntObjectPersonalityBuilder from(OntPersonality from) {
return new OntObjectPersonalityBuilder()
.addPersonality(OntPersonality.asJenaPersonality(from))
.setPunnings(from.getPunnings())
.setBuiltins(from.getBuiltins())
.setReserved(from.getReserved())
.setConfig(from.getConfig());
}
private static X require(X obj, Class type) {
if (obj == null) {
throw new IllegalStateException("The " + type.getSimpleName() + " Vocabulary must be present in builder.");
}
return obj;
}
@SuppressWarnings("rawtypes")
private static V hasSpec(V voc, Class... types) {
Objects.requireNonNull(voc);
@SuppressWarnings("unchecked") Set> errors = Arrays.stream(types).filter(x -> !voc.supports(x)).collect(Collectors.toSet());
if (errors.isEmpty()) return voc;
throw new IllegalArgumentException("The vocabulary " + voc + " has missed required types: " + errors);
}
/**
* Makes a full copy of this builder.
*
* @return {@link OntObjectPersonalityBuilder}, a copy
*/
public OntObjectPersonalityBuilder copy() {
OntObjectPersonalityBuilder res = new OntObjectPersonalityBuilder();
res.stdFactories.putAll(this.stdFactories);
res.extFactories.putAll(this.extFactories);
res.setName(name);
if (punnings != null) res.setPunnings(punnings);
if (builtins != null) res.setBuiltins(builtins);
if (reserved != null) res.setReserved(reserved);
if (config != null) res.setConfig(config);
return res;
}
/**
* Adds all factories from the specified builder.
* @param other {@link OntObjectPersonalityBuilder}
* @return this builder
*/
public OntObjectPersonalityBuilder add(OntObjectPersonalityBuilder other) {
extFactories.putAll(other.extFactories);
stdFactories.putAll(other.stdFactories);
return this;
}
/**
* Associates the specified {@link EnhNodeFactory factory} with the specified {@link OntObject object} type.
* If the builder previously contained a mapping for the object type,
* the old factory is replaced by the specified factory.
*
* Note: the {@link EnhNodeFactory factory} must not explicitly refer to another factory,
* instead it may contain implicit references through
* {@link OntEnhGraph#asPersonalityModel(EnhGraph)} method.
* For example, if you need a check, that some {@link Node node} is an OWL-Class inside your factory,
* you can use {@link OntEnhGraph#canAs(Class, Node, EnhGraph)}
* with the type {@link OntClass.Named}.
*
* @param type {@code Class}-type of the concrete {@link OntObject}.
* @param factory {@link EnhNodeFactory} the factory to produce the instances of the {@code type}
* @return this builder
*/
@SuppressWarnings("javadoc")
public OntObjectPersonalityBuilder add(Class extends OntObject> type, EnhNodeFactory factory) {
return add(type, config -> factory);
}
/**
* Associates the specified {@link EnhNodeFactory factory} producer with the specified {@link OntObject object} type.
* If the builder previously contained a mapping for the object type,
* the old factory is replaced by the specified factory.
*
* Note: the {@link EnhNodeFactory factory} must not explicitly refer to another factory,
* instead it may contain implicit references through
* {@link OntEnhGraph#asPersonalityModel(EnhGraph)} method.
* For example, if you need a check, that some {@link Node node} is an OWL-Class inside your factory,
* you can use {@link OntEnhGraph#canAs(Class, Node, EnhGraph)}
* with the type {@link OntClass.Named}.
*
* @param type {@code Class}-type of the concrete {@link OntObject}.
* @param factory {@code Function}, providing {@link EnhNodeFactory} by the {@link OntConfig}
* @return this builder
*/
@SuppressWarnings("javadoc")
public OntObjectPersonalityBuilder add(Class extends OntObject> type, Function factory) {
extFactories.put(type, factory);
return this;
}
/**
* Removes object factory.
*
* @param type {@code Class}-type of {@link OntObject}
* @return this builder
*/
public OntObjectPersonalityBuilder remove(Class extends OntObject> type) {
extFactories.remove(type);
stdFactories.remove(type);
return this;
}
/**
* Adds everything from the specified {@link Personality Jena Personality} to the existing internal collection.
*
* @param from {@link Personality} with generic type {@link RDFNode}, not {@code null}
* @return this builder
* @see Personality#add(Personality)
*/
public OntObjectPersonalityBuilder addPersonality(Personality from) {
stdFactories.putAll(new JenaPersonalityAccessor(from).getMap());
return this;
}
/**
* Sets identifier of language profile ("OWL", "RDF").
*
* @param profileName String, can be {@code null}
* @return this builder
*/
public OntObjectPersonalityBuilder setName(String profileName) {
this.name = profileName;
return this;
}
/**
* Sets a new punnings personality vocabulary.
*
* @param punnings {@link OntPersonality.Punnings}, not {@code null}
* @return this builder
*/
public OntObjectPersonalityBuilder setPunnings(OntPersonality.Punnings punnings) {
this.punnings = hasSpec(punnings, getEntityTypes());
return this;
}
/**
* Sets a new builtins personality vocabulary.
*
* @param builtins {@link OntPersonality.Builtins}, not {@code null}
* @return this builder
*/
public OntObjectPersonalityBuilder setBuiltins(OntPersonality.Builtins builtins) {
this.builtins = hasSpec(builtins, getEntityTypes());
return this;
}
/**
* Sets a new reserved personality vocabulary.
*
* @param reserved {@link OntPersonality.Reserved}, not {@code null}
* @return this builder
*/
public OntObjectPersonalityBuilder setReserved(OntPersonality.Reserved reserved) {
this.reserved = hasSpec(reserved, Resource.class, Property.class);
return this;
}
/**
* Sets config, which controls OntModel behaviour.
*
* @param config {@link OntConfig}, not {@code null}
* @return this builder
*/
public OntObjectPersonalityBuilder setConfig(OntConfig config) {
this.config = Objects.requireNonNull(config);
return this;
}
/**
* Builds a new personality configuration.
*
* @return {@link OntPersonality}, fresh instance
* @throws IllegalStateException in case the builder does not contain require components
*/
public OntPersonality build() throws IllegalStateException {
OntConfig config = config();
OntPersonality.Punnings punnings = punnings();
OntPersonality.Builtins builtins = builtins();
OntPersonality.Reserved reserved = reserved();
OntPersonalityImpl res = new OntPersonalityImpl(name, config, punnings, builtins, reserved);
stdFactories.forEach(res::add);
extFactories.forEach((type, factory) -> res.register(type, factory.apply(config)));
return res;
}
private Class>[] getEntityTypes() {
return OntEntity.TYPES.toArray(Class[]::new);
}
private OntPersonality.Punnings punnings() {
return require(punnings, OntPersonality.Punnings.class);
}
private OntPersonality.Builtins builtins() {
return require(builtins, OntPersonality.Builtins.class);
}
private OntPersonality.Reserved reserved() {
return require(reserved, OntPersonality.Reserved.class);
}
private OntConfig config() {
return Objects.requireNonNull(config, "No config is set");
}
private static class JenaPersonalityAccessor extends Personality {
public JenaPersonalityAccessor(Personality other) {
super(other);
}
@Override
protected Map, Implementation> getMap() {
return super.getMap();
}
}
}