AbstractConverter.java
/*
* #%L
* prolobjectlink-jpi
* %%
* Copyright (C) 2019 Prolobjectlink Project
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
package io.github.prolobjectlink.prolog;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Partial implementation of {@link PrologConverter} interface.
*
* @author Jose Zalacain
* @since 1.0
*/
public abstract class AbstractConverter<T> implements PrologConverter<T> {
public static final String SIMPLE_ATOM_REGEX = ".|[a-z][A-Za-z0-9_]*";
private static final String IMPOSIBLE_CONVERT = "Impossible convert '";
private static final String FROM = "' from '";
private static final String TO = "' to '";
protected final HashMap<String, PrologVariable> sharedVariables;
protected final HashMap<String, T> sharedPrologVariables;
protected final PrologProvider provider;
protected AbstractConverter() {
sharedVariables = new HashMap<String, PrologVariable>();
sharedPrologVariables = new HashMap<String, T>();
provider = createProvider();
}
protected final PrologLogger getLogger() {
return provider.getLogger();
}
private final boolean isQuoted(String functor) {
if (!functor.isEmpty()) {
char beginChar = functor.charAt(0);
char endChar = functor.charAt(functor.length() - 1);
return beginChar == '\'' && endChar == '\'';
}
return false;
}
public final String removeQuoted(String functor) {
if (isQuoted(functor)) {
String newFunctor = "";
newFunctor += functor.substring(1, functor.length() - 1);
return newFunctor;
}
return functor;
}
public final PrologTerm[] toTermArray(T[] terms) {
PrologTerm[] iTerms = new PrologTerm[terms.length];
for (int i = 0; i < terms.length; i++) {
iTerms[i] = toTerm(terms[i]);
}
return iTerms;
}
public final PrologTerm[][] toTermMatrix(T[][] terms) {
int n = terms.length;
int m = terms[0].length;
PrologTerm[][] iTerms = new PrologTerm[n][m];
for (int i = 0; i < n; i++) {
iTerms[i] = toTermArray(terms[i]);
}
return iTerms;
}
public final Map<String, PrologTerm> toTermMap(Map<String, T> map) {
Map<String, PrologTerm> solutionMap = new HashMap<String, PrologTerm>(map.size());
Set<String> keys = map.keySet();
for (String key : keys) {
solutionMap.put(key, toTerm(map.get(key)));
}
return solutionMap;
}
public final Map<String, PrologTerm>[] toTermMapArray(Map<String, T>[] map) {
Map<String, PrologTerm>[] solutions = new Map[map.length];
for (int i = 0; i < map.length; i++) {
solutions[i] = toTermMap(map[i]);
}
return solutions;
}
public final <K extends PrologTerm> K toTerm(Object o, Class<K> from) {
Class<T> clazz = getGenericClass();
if (clazz != null && clazz.isAssignableFrom(o.getClass())) {
PrologTerm term = toTerm((T) o);
if (from.isAssignableFrom(term.getClass())) {
return from.cast(term);
}
}
throw new PrologError(
IMPOSIBLE_CONVERT + o + FROM + from + "'"
);
}
public final <K extends PrologTerm> K[] toTermArray(Object[] os, Class<K[]> from) {
Class<T> clazz = getGenericClass();
Class<?> cType = os.getClass().getComponentType();
if (clazz != null && clazz.isAssignableFrom(cType)) {
PrologTerm[] terms = toTermArray((T[]) os);
if (from.isAssignableFrom(terms.getClass())) {
return from.cast(terms);
}
}
throw new PrologError(
IMPOSIBLE_CONVERT +
Arrays.toString(os) +
FROM + from + "'"
);
}
public final <K extends PrologTerm> K[][] toTermMatrix(Object[][] oss, Class<K[][]> from) {
Class<T> clazz = getGenericClass();
Class<?> cType = oss.getClass().getComponentType();
Class<?> c = Array.newInstance(clazz, 0).getClass();
if (c.isAssignableFrom(cType)) {
PrologTerm[][] terms = toTermMatrix((T[][]) oss);
if (from.isAssignableFrom(terms.getClass())) {
return from.cast(terms);
}
}
throw new PrologError(
IMPOSIBLE_CONVERT +
Arrays.toString(oss) +
FROM + from + "'"
);
}
public final <K extends PrologTerm, V extends Object> Map<String, PrologTerm> toTermMap(Map<String, V> map,
Class<K> from) {
Map<String, PrologTerm> solutionMap = new HashMap<String, PrologTerm>(map.size());
Set<String> keys = map.keySet();
for (String key : keys) {
Object o = map.get(key);
PrologTerm term = toTerm(o, from);
solutionMap.put(key, term);
}
return solutionMap;
}
public final <K extends PrologTerm, V extends Object> Map<String, PrologTerm>[] toTermMapArray(Map<String, V>[] map,
Class<K> from) {
Map<String, PrologTerm>[] solutions = new Map[map.length];
for (int i = 0; i < map.length; i++) {
solutions[i] = toTermMap(map[i], from);
}
return solutions;
}
public final <K> K fromTerm(PrologTerm term, Class<K> to) {
T t = fromTerm(term);
if (to.isAssignableFrom(t.getClass())) {
return to.cast(t);
}
throw new PrologError(
IMPOSIBLE_CONVERT + term + TO + to + "'"
);
}
public final <K> K[] fromTermArray(PrologTerm[] terms, Class<K[]> to) {
T[] ts = fromTermArray(terms);
if (to.isAssignableFrom(ts.getClass())) {
return to.cast(ts);
}
throw new PrologError(
IMPOSIBLE_CONVERT + Arrays.toString(terms) + TO + to + "'"
);
}
public final <K> K fromTerm(PrologTerm head, PrologTerm[] body, Class<K> to) {
T t = fromTerm(head, body);
if (to.isAssignableFrom(t.getClass())) {
return to.cast(t);
}
throw new PrologError(
IMPOSIBLE_CONVERT +
head + " and " + Arrays.toString(body) +
TO + to + "'"
);
}
public final Class<T> getGenericClass() {
Class<T> templateClass = null;
Type[] generics = getClass().getGenericInterfaces();
if (generics.length == 1 && generics[0] instanceof ParameterizedType) {
ParameterizedType parameterized = (ParameterizedType) generics[0];
Type type = parameterized.getActualTypeArguments()[0];
if (type instanceof Class<?>) {
templateClass = (Class<T>) type;
}
}
return templateClass;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((sharedPrologVariables == null) ? 0 : sharedPrologVariables.hashCode());
result = prime * result + ((sharedVariables == null) ? 0 : sharedVariables.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AbstractConverter<?> other = (AbstractConverter<?>) obj;
if (sharedPrologVariables == null) {
if (other.sharedPrologVariables != null)
return false;
} else if (!sharedPrologVariables.equals(other.sharedPrologVariables)) {
return false;
}
if (sharedVariables == null) {
if (other.sharedVariables != null)
return false;
} else if (!sharedVariables.equals(other.sharedVariables)) {
return false;
}
return true;
}
}