View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * Permission is hereby granted, free of charge, to any person obtaining a copy
8    * of this software and associated documentation files (the "Software"), to deal
9    * in the Software without restriction, including without limitation the rights
10   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11   * copies of the Software, and to permit persons to whom the Software is
12   * furnished to do so, subject to the following conditions:
13   * 
14   * The above copyright notice and this permission notice shall be included in
15   * all copies or substantial portions of the Software.
16   * 
17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23   * THE SOFTWARE.
24   * #L%
25   */
26  package io.github.prolobjectlink.prolog;
27  
28  import java.lang.reflect.Array;
29  import java.lang.reflect.ParameterizedType;
30  import java.lang.reflect.Type;
31  import java.util.Arrays;
32  import java.util.HashMap;
33  import java.util.Map;
34  import java.util.Set;
35  
36  /**
37   * Partial implementation of {@link PrologConverter} interface.
38   * 
39   * @author Jose Zalacain
40   * @since 1.0
41   */
42  public abstract class AbstractConverter<T> implements PrologConverter<T> {
43  
44  	public static final String SIMPLE_ATOM_REGEX = ".|[a-z][A-Za-z0-9_]*";
45  	private static final String IMPOSIBLE_CONVERT = "Impossible convert '";
46  	private static final String FROM = "' from '";
47  	private static final String TO = "' to '";
48  
49  	protected final HashMap<String, PrologVariable> sharedVariables;
50  	protected final HashMap<String, T> sharedPrologVariables;
51  	protected final PrologProvider provider;
52  
53  	protected AbstractConverter() {
54  		sharedVariables = new HashMap<String, PrologVariable>();
55  		sharedPrologVariables = new HashMap<String, T>();
56  		provider = createProvider();
57  	}
58  
59  	protected final PrologLogger getLogger() {
60  		return provider.getLogger();
61  	}
62  
63  	private final boolean isQuoted(String functor) {
64  		if (!functor.isEmpty()) {
65  			char beginChar = functor.charAt(0);
66  			char endChar = functor.charAt(functor.length() - 1);
67  			return beginChar == '\'' && endChar == '\'';
68  		}
69  		return false;
70  	}
71  
72  	public final String removeQuoted(String functor) {
73  		if (isQuoted(functor)) {
74  			String newFunctor = "";
75  			newFunctor += functor.substring(1, functor.length() - 1);
76  			return newFunctor;
77  		}
78  		return functor;
79  	}
80  
81  	public final PrologTerm[] toTermArray(T[] terms) {
82  		PrologTerm[] iTerms = new PrologTerm[terms.length];
83  		for (int i = 0; i < terms.length; i++) {
84  			iTerms[i] = toTerm(terms[i]);
85  		}
86  		return iTerms;
87  	}
88  
89  	public final PrologTerm[][] toTermMatrix(T[][] terms) {
90  		int n = terms.length;
91  		int m = terms[0].length;
92  		PrologTerm[][] iTerms = new PrologTerm[n][m];
93  		for (int i = 0; i < n; i++) {
94  			iTerms[i] = toTermArray(terms[i]);
95  		}
96  		return iTerms;
97  	}
98  
99  	public final Map<String, PrologTerm> toTermMap(Map<String, T> map) {
100 		Map<String, PrologTerm> solutionMap = new HashMap<String, PrologTerm>(map.size());
101 		Set<String> keys = map.keySet();
102 		for (String key : keys) {
103 			solutionMap.put(key, toTerm(map.get(key)));
104 		}
105 		return solutionMap;
106 	}
107 
108 	public final Map<String, PrologTerm>[] toTermMapArray(Map<String, T>[] map) {
109 		Map<String, PrologTerm>[] solutions = new Map[map.length];
110 		for (int i = 0; i < map.length; i++) {
111 			solutions[i] = toTermMap(map[i]);
112 		}
113 		return solutions;
114 	}
115 
116 	public final <K extends PrologTerm> K toTerm(Object o, Class<K> from) {
117 		Class<T> clazz = getGenericClass();
118 		if (clazz != null && clazz.isAssignableFrom(o.getClass())) {
119 			PrologTerm term = toTerm((T) o);
120 			if (from.isAssignableFrom(term.getClass())) {
121 				return from.cast(term);
122 			}
123 		}
124 		throw new PrologError(
125 
126 				IMPOSIBLE_CONVERT + o + FROM + from + "'"
127 
128 		);
129 	}
130 
131 	public final <K extends PrologTerm> K[] toTermArray(Object[] os, Class<K[]> from) {
132 		Class<T> clazz = getGenericClass();
133 		Class<?> cType = os.getClass().getComponentType();
134 		if (clazz != null && clazz.isAssignableFrom(cType)) {
135 			PrologTerm[] terms = toTermArray((T[]) os);
136 			if (from.isAssignableFrom(terms.getClass())) {
137 				return from.cast(terms);
138 			}
139 		}
140 		throw new PrologError(
141 
142 				IMPOSIBLE_CONVERT +
143 
144 						Arrays.toString(os) +
145 
146 						FROM + from + "'"
147 
148 		);
149 	}
150 
151 	public final <K extends PrologTerm> K[][] toTermMatrix(Object[][] oss, Class<K[][]> from) {
152 		Class<T> clazz = getGenericClass();
153 		Class<?> cType = oss.getClass().getComponentType();
154 		Class<?> c = Array.newInstance(clazz, 0).getClass();
155 		if (c.isAssignableFrom(cType)) {
156 			PrologTerm[][] terms = toTermMatrix((T[][]) oss);
157 			if (from.isAssignableFrom(terms.getClass())) {
158 				return from.cast(terms);
159 			}
160 		}
161 		throw new PrologError(
162 
163 				IMPOSIBLE_CONVERT +
164 
165 						Arrays.toString(oss) +
166 
167 						FROM + from + "'"
168 
169 		);
170 	}
171 
172 	public final <K extends PrologTerm, V extends Object> Map<String, PrologTerm> toTermMap(Map<String, V> map,
173 			Class<K> from) {
174 		Map<String, PrologTerm> solutionMap = new HashMap<String, PrologTerm>(map.size());
175 		Set<String> keys = map.keySet();
176 		for (String key : keys) {
177 			Object o = map.get(key);
178 			PrologTerm term = toTerm(o, from);
179 			solutionMap.put(key, term);
180 		}
181 		return solutionMap;
182 	}
183 
184 	public final <K extends PrologTerm, V extends Object> Map<String, PrologTerm>[] toTermMapArray(Map<String, V>[] map,
185 			Class<K> from) {
186 		Map<String, PrologTerm>[] solutions = new Map[map.length];
187 		for (int i = 0; i < map.length; i++) {
188 			solutions[i] = toTermMap(map[i], from);
189 		}
190 		return solutions;
191 	}
192 
193 	public final <K> K fromTerm(PrologTerm term, Class<K> to) {
194 		T t = fromTerm(term);
195 		if (to.isAssignableFrom(t.getClass())) {
196 			return to.cast(t);
197 		}
198 		throw new PrologError(
199 
200 				IMPOSIBLE_CONVERT + term + TO + to + "'"
201 
202 		);
203 	}
204 
205 	public final <K> K[] fromTermArray(PrologTerm[] terms, Class<K[]> to) {
206 		T[] ts = fromTermArray(terms);
207 		if (to.isAssignableFrom(ts.getClass())) {
208 			return to.cast(ts);
209 		}
210 		throw new PrologError(
211 
212 				IMPOSIBLE_CONVERT + Arrays.toString(terms) + TO + to + "'"
213 
214 		);
215 	}
216 
217 	public final <K> K fromTerm(PrologTerm head, PrologTerm[] body, Class<K> to) {
218 		T t = fromTerm(head, body);
219 		if (to.isAssignableFrom(t.getClass())) {
220 			return to.cast(t);
221 		}
222 		throw new PrologError(
223 
224 				IMPOSIBLE_CONVERT +
225 
226 						head + " and " + Arrays.toString(body) +
227 
228 						TO + to + "'"
229 
230 		);
231 	}
232 
233 	public final Class<T> getGenericClass() {
234 		Class<T> templateClass = null;
235 		Type[] generics = getClass().getGenericInterfaces();
236 		if (generics.length == 1 && generics[0] instanceof ParameterizedType) {
237 			ParameterizedType parameterized = (ParameterizedType) generics[0];
238 			Type type = parameterized.getActualTypeArguments()[0];
239 			if (type instanceof Class<?>) {
240 				templateClass = (Class<T>) type;
241 			}
242 		}
243 		return templateClass;
244 	}
245 
246 	@Override
247 	public int hashCode() {
248 		final int prime = 31;
249 		int result = 1;
250 		result = prime * result + ((sharedPrologVariables == null) ? 0 : sharedPrologVariables.hashCode());
251 		result = prime * result + ((sharedVariables == null) ? 0 : sharedVariables.hashCode());
252 		return result;
253 	}
254 
255 	@Override
256 	public boolean equals(Object obj) {
257 		if (this == obj)
258 			return true;
259 		if (obj == null)
260 			return false;
261 		if (getClass() != obj.getClass())
262 			return false;
263 		AbstractConverter<?> other = (AbstractConverter<?>) obj;
264 		if (sharedPrologVariables == null) {
265 			if (other.sharedPrologVariables != null)
266 				return false;
267 		} else if (!sharedPrologVariables.equals(other.sharedPrologVariables)) {
268 			return false;
269 		}
270 		if (sharedVariables == null) {
271 			if (other.sharedVariables != null)
272 				return false;
273 		} else if (!sharedVariables.equals(other.sharedVariables)) {
274 			return false;
275 		}
276 		return true;
277 	}
278 
279 }