View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jpl
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation, either version 2.1 of the
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
20   * #L%
21   */
22  package io.github.prolobjectlink.prolog.jpl;
23  
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.NoSuchElementException;
31  
32  import io.github.prolobjectlink.prolog.AbstractEngine;
33  import io.github.prolobjectlink.prolog.AbstractIterator;
34  import io.github.prolobjectlink.prolog.AbstractQuery;
35  import io.github.prolobjectlink.prolog.PrologError;
36  import io.github.prolobjectlink.prolog.PrologQuery;
37  import io.github.prolobjectlink.prolog.PrologTerm;
38  import jpl.PrologException;
39  import jpl.Query;
40  import jpl.Term;
41  import jpl.Util;
42  import jpl.Variable;
43  
44  /**
45   * 
46   * @author Jose Zalacain
47   * @since 1.0
48   */
49  final class JplQuery extends AbstractQuery implements PrologQuery {
50  
51  	private String stringQuery;
52  	private Map<String, PrologTerm>[] solutions;
53  	private Iterator<Map<String, PrologTerm>> iter;
54  
55  	private final List<String> variables = new ArrayList<String>();
56  
57  	private void enumerateVariables(List<String> vector, Term term) {
58  		if (!(term instanceof Variable)) {
59  			Term[] terms = term.args();
60  			for (Term t : terms) {
61  				enumerateVariables(vector, t);
62  			}
63  		} else if (!vector.contains(term.name())) {
64  			vector.add(term.name());
65  		}
66  	}
67  
68  	JplQuery(AbstractEngine engine, String file, String stringQuery) {
69  		super(engine);
70  
71  		if (stringQuery != null && stringQuery.length() > 0) {
72  			this.stringQuery = stringQuery;
73  
74  			// saving variable order
75  			enumerateVariables(variables, Util.textToTerm(stringQuery));
76  
77  			try {
78  
79  				Query.hasSolution("consult('" + file + "')");
80  				Query query = new Query(stringQuery);
81  				Map<String, Term>[] solve = query.allSolutions();
82  				solutions = toTermMapArray(solve, PrologTerm.class);
83  				iter = new JplQueryIter(solutions);
84  
85  			} catch (PrologException e) {
86  				// getLogger().error(getClass(), PrologLogger.RUNTIME_ERROR, e)
87  				Map<String, PrologTerm> m = new HashMap<String, PrologTerm>();
88  				JplReference prologexception = new JplReference(getProvider(), e);
89  				Term error = e.term();
90  				Term exception = error.arg(1);
91  				Term ref = exception.arg(1);
92  				if (ref.isJRef()) {
93  					Object object = ref.jrefToObject();
94  					if (object instanceof Throwable) {
95  						Throwable k = (Throwable) object;
96  						// getLogger().error(getClass(), PrologLogger.RUNTIME_ERROR, k)
97  						JplReference javaexception = new JplReference(getProvider(), k);
98  						m.put("PrologException", prologexception);
99  						m.put("JavaException", javaexception);
100 						solutions = new Map[] { m };
101 					}
102 				}
103 			}
104 		}
105 
106 	}
107 
108 	public boolean hasSolution() {
109 		return iter != null && iter.hasNext();
110 	}
111 
112 	public boolean hasMoreSolutions() {
113 		return iter != null && iter.hasNext();
114 	}
115 
116 	public PrologTerm[] oneSolution() {
117 		int index = 0;
118 		Map<String, PrologTerm> solution = oneVariablesSolution();
119 		PrologTerm[] array = new PrologTerm[solution.size()];
120 		for (Iterator<String> i = variables.iterator(); i.hasNext();) {
121 			array[index++] = solution.get(i.next());
122 		}
123 		return array;
124 	}
125 
126 	public Map<String, PrologTerm> oneVariablesSolution() {
127 		return solutions.length > 0 ? solutions[0] : new HashMap<String, PrologTerm>();
128 	}
129 
130 	public PrologTerm[] nextSolution() {
131 		int index = 0;
132 		Map<String, PrologTerm> solution = nextVariablesSolution();
133 		PrologTerm[] array = new PrologTerm[solution.size()];
134 		for (Iterator<String> i = variables.iterator(); i.hasNext();) {
135 			array[index++] = solution.get(i.next());
136 		}
137 		return array;
138 	}
139 
140 	public Map<String, PrologTerm> nextVariablesSolution() {
141 		return iter.next();
142 	}
143 
144 	public PrologTerm[][] nSolutions(int n) {
145 		if (n > 0) {
146 			// m:solutionSize
147 			int m = 0;
148 			int index = 0;
149 			ArrayList<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
150 			while (hasNext() && index < n) {
151 				PrologTerm[] solution = nextSolution();
152 				m = solution.length > m ? solution.length : m;
153 				index++;
154 				all.add(solution);
155 			}
156 
157 			PrologTerm[][] allSolutions = new PrologTerm[n][m];
158 			for (int i = 0; i < n; i++) {
159 				PrologTerm[] solution = all.get(i);
160 				for (int j = 0; j < m; j++) {
161 					allSolutions[i][j] = solution[j];
162 				}
163 			}
164 			return allSolutions;
165 		}
166 		throw new PrologError("Impossible find " + n + " solutions");
167 	}
168 
169 	public Map<String, PrologTerm>[] nVariablesSolutions(int n) {
170 		return Arrays.copyOf(solutions, n);
171 	}
172 
173 	public PrologTerm[][] allSolutions() {
174 		// n:solutionCount, m:solutionSize
175 		int n = 0;
176 		int m = 0;
177 		ArrayList<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
178 		while (hasMoreSolutions()) {
179 			PrologTerm[] solution = nextSolution();
180 			m = solution.length > m ? solution.length : m;
181 			n++;
182 			all.add(solution);
183 		}
184 
185 		PrologTerm[][] allSolutions = new PrologTerm[n][m];
186 		for (int i = 0; i < n; i++) {
187 			PrologTerm[] solution = all.get(i);
188 			for (int j = 0; j < m; j++) {
189 				allSolutions[i][j] = solution[j];
190 			}
191 		}
192 		return allSolutions;
193 	}
194 
195 	public Map<String, PrologTerm>[] allVariablesSolutions() {
196 		return solutions;
197 	}
198 
199 	public void dispose() {
200 		iter = null;
201 		variables.clear();
202 		int l = solutions.length;
203 		for (int i = 0; i < l; i++) {
204 			solutions[i].clear();
205 			solutions[i] = null;
206 		}
207 		solutions = null;
208 	}
209 
210 	public List<Map<String, PrologTerm>> all() {
211 		List<Map<String, PrologTerm>> l = new ArrayList<Map<String, PrologTerm>>();
212 		for (Map<String, PrologTerm> map : solutions) {
213 			l.add(map);
214 		}
215 		return l;
216 	}
217 
218 	@Override
219 	public int hashCode() {
220 		final int prime = 31;
221 		int result = super.hashCode();
222 		result = prime * result + stringQuery.hashCode();
223 		result = prime * result + variables.hashCode();
224 		return result;
225 	}
226 
227 	@Override
228 	public boolean equals(Object obj) {
229 		if (this == obj) {
230 			return true;
231 		}
232 		if (!super.equals(obj)) {
233 			return false;
234 		}
235 		if (getClass() != obj.getClass()) {
236 			return false;
237 		}
238 		JplQuery other = (JplQuery) obj;
239 		return variables.equals(other.variables);
240 	}
241 
242 	@Override
243 	public String toString() {
244 		return stringQuery;
245 	}
246 
247 	private class JplQueryIter extends AbstractIterator<Map<String, PrologTerm>>
248 			implements Iterator<Map<String, PrologTerm>> {
249 
250 		private int nextIndex;
251 		private final Map<String, PrologTerm>[] maps;
252 
253 		private JplQueryIter(Map<String, PrologTerm>[] maps) {
254 			this.maps = maps;
255 		}
256 
257 		public boolean hasNext() {
258 			return nextIndex < maps.length;
259 		}
260 
261 		public Map<String, PrologTerm> next() {
262 			if (!hasNext()) {
263 				throw new NoSuchElementException();
264 			}
265 			return maps[nextIndex++];
266 		}
267 
268 	}
269 
270 }