svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.remoteclient / src / main / java / org / gvsig / remoteclient / wfs / filters / filterencoding / FilterEncoding.java @ 40769
History | View | Annotate | Download (17.7 KB)
1 | 40559 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | *
|
||
4 | * Copyright (C) 2007-2013 gvSIG Association.
|
||
5 | *
|
||
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | * as published by the Free Software Foundation; either version 3
|
||
9 | * of the License, or (at your option) any later version.
|
||
10 | *
|
||
11 | * This program is distributed in the hope that it will be useful,
|
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 | * GNU General Public License for more details.
|
||
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
19 | * MA 02110-1301, USA.
|
||
20 | *
|
||
21 | * For any additional information, do not hesitate to contact us
|
||
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | */
|
||
24 | 40435 | jjdelcerro | |
25 | package org.gvsig.remoteclient.wfs.filters.filterencoding; |
||
26 | import java.util.ArrayList; |
||
27 | import java.util.Hashtable; |
||
28 | import java.util.Iterator; |
||
29 | import java.util.Set; |
||
30 | |||
31 | import org.gvsig.compat.CompatLocator; |
||
32 | import org.gvsig.compat.lang.StringUtils; |
||
33 | import org.gvsig.remoteclient.wfs.WFSStatus; |
||
34 | import org.gvsig.remoteclient.wfs.edition.WFSTTags; |
||
35 | import org.gvsig.remoteclient.wfs.filters.AbstractFilter; |
||
36 | import org.gvsig.remoteclient.wfs.filters.BinaryTree; |
||
37 | import org.gvsig.remoteclient.wfs.filters.BinaryTree.Node; |
||
38 | import org.gvsig.remoteclient.wfs.filters.DefaultSQLExpressionFormat; |
||
39 | import org.gvsig.remoteclient.wfs.filters.ISQLExpressionFormat; |
||
40 | import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_0_0.EnvelopeFEQuery1_0_0; |
||
41 | import org.gvsig.remoteclient.wfs.filters.filterencoding.wfs_1_1_0.EnvelopeFEQuery1_1_0; |
||
42 | import org.gvsig.remoteclient.wfs.filters.operations.WFSEnvelopeFilterOperation; |
||
43 | import org.gvsig.remoteclient.wfs.filters.operations.WFSGeometryFilterOperation; |
||
44 | import org.gvsig.remoteclient.wfs.filters.operations.WFSSpatialFilterOperation; |
||
45 | |||
46 | /**
|
||
47 | * This class implements the Filter Encoding Language. It is used to
|
||
48 | * create querys in this language
|
||
49 | *
|
||
50 | * Name: OpenGIS? Filter Encoding Implementation Specification
|
||
51 | * Version: 1.1.0
|
||
52 | * Project Document: OGC 04-095
|
||
53 | * @see http://portal.opengeospatial.org/files/?artifact_id=8340
|
||
54 | *
|
||
55 | * @author Jorge Piera Llodra (piera_jor@gva.es)
|
||
56 | */
|
||
57 | public class FilterEncoding extends AbstractFilter { |
||
58 | public static final int RELATIONSHIP_PROPERTY = 0; |
||
59 | public static final int RELATIONSHIP_VAUES = 1; |
||
60 | |||
61 | private StringBuffer currentQuery = null; |
||
62 | //Operation types
|
||
63 | private static final int OPERATION_PROPERTYNAME = 0; |
||
64 | private static final int OPERATION_LITERAL = 1; |
||
65 | |||
66 | //Filter namespace.
|
||
67 | private String nameSpacePrefix = null; |
||
68 | private String nameSpaceLocation = null; |
||
69 | |||
70 | //If the Filter can have blanckSpaces
|
||
71 | private boolean hasBlankSpaces = true; |
||
72 | private String defaultBlankSpace = "%20"; |
||
73 | //This character must be replaced by any set of characters (typically "*")
|
||
74 | private String wildCardChar = null; |
||
75 | //This character must be replaced by one character (typically "?")
|
||
76 | private String singleChar = null; |
||
77 | //Escape character (typically "\")
|
||
78 | private String escapeChar = null; |
||
79 | //Default values
|
||
80 | public static final String DEFAULT_NAMESPACE_PREFIX = "ogc"; |
||
81 | public static final String DEFAULT_WILDCARD = "*"; |
||
82 | public static final String DEFAULT_SINGLECHAR = "?"; |
||
83 | public static final String DEFAULT_ESCAPE = "\\"; |
||
84 | public static final String DEFAULT_NAMESPACE = "xmlns:ogc=\"http://www.opengis.net/ogc\""; |
||
85 | |||
86 | private Hashtable filterAttributes = new Hashtable(); |
||
87 | |||
88 | /**
|
||
89 | * If the namespace XML is qualified
|
||
90 | */
|
||
91 | private boolean isQualified = false; |
||
92 | |||
93 | private static final StringUtils stringUtils = CompatLocator.getStringUtils(); |
||
94 | |||
95 | /**
|
||
96 | * Create a new Filter Encoding Parser
|
||
97 | *
|
||
98 | *
|
||
99 | * @param nameSpacePrefix
|
||
100 | * Filter namespace. (typically "ogc")
|
||
101 | * @param wildCardChar
|
||
102 | * This character must be replaced by any set of characters (typically "*")
|
||
103 | * @param singleChar
|
||
104 | * This character must be replaced by one character (typically "?")
|
||
105 | * @param escape
|
||
106 | * Escape character
|
||
107 | * @param filterAttribute Sometimes, "Field" label needs an attribute.
|
||
108 | */
|
||
109 | public FilterEncoding(ISQLExpressionFormat formatter,String namesPacePrefix, String wildCard, String singleChar, String escape, Hashtable filterAttributes) { |
||
110 | super(formatter);
|
||
111 | if (namesPacePrefix == null){ |
||
112 | setQualified(false);
|
||
113 | }else{
|
||
114 | setQualified(true);
|
||
115 | } |
||
116 | this.wildCardChar = wildCard;
|
||
117 | this.singleChar = singleChar;
|
||
118 | this.escapeChar = escape;
|
||
119 | this.filterAttributes = filterAttributes;
|
||
120 | } |
||
121 | |||
122 | |||
123 | /**
|
||
124 | * Create a new Filter Encoding Parser
|
||
125 | * @param formatter
|
||
126 | */
|
||
127 | public FilterEncoding(ISQLExpressionFormat formatter) {
|
||
128 | this(formatter,null,DEFAULT_WILDCARD,DEFAULT_SINGLECHAR, |
||
129 | DEFAULT_ESCAPE,new Hashtable()); |
||
130 | } |
||
131 | |||
132 | /**
|
||
133 | * Create a new Filter Encoding Parser
|
||
134 | */
|
||
135 | FilterEncoding() { |
||
136 | this(new DefaultSQLExpressionFormat()); |
||
137 | } |
||
138 | |||
139 | /**
|
||
140 | * Create a new Filter Encoding Parser
|
||
141 | */
|
||
142 | public FilterEncoding(WFSStatus status) {
|
||
143 | this();
|
||
144 | this.nameSpacePrefix = status.getNamespacePrefix();
|
||
145 | this.nameSpaceLocation = status.getNamespaceLocation();
|
||
146 | setQueryByAttribute(status.getFilterByAttribute()); |
||
147 | clearSpatialFilters(); |
||
148 | addSpatialFilter(status.getFilterByArea()); |
||
149 | } |
||
150 | |||
151 | /*
|
||
152 | * (non-Javadoc)
|
||
153 | * @see org.gvsig.remoteClient.filterEncoding.QueryLanguage#toString(org.gvsig.remoteClient.filterEncoding.BinaryTree)
|
||
154 | */
|
||
155 | public String toString(BinaryTree tree, String version) { |
||
156 | //If is a filter by ids...
|
||
157 | StringBuffer idQuery = null; |
||
158 | if (getIds() != null){ |
||
159 | idQuery = new StringBuffer(); |
||
160 | ArrayList ids = getIds();
|
||
161 | for (int i=0 ; i<ids.size() ; i++){ |
||
162 | if (ids.get(i) != null){ |
||
163 | Hashtable attributes = new Hashtable(); |
||
164 | attributes.put("fid","\"" + ids.get(i).toString() + "\""); |
||
165 | idQuery.append(setTag("FeatureId", attributes, null)); |
||
166 | } |
||
167 | } |
||
168 | return enclosesWithFilterTag(idQuery.toString());
|
||
169 | } |
||
170 | //If is a filter by attributes...
|
||
171 | String filterQuery = null; |
||
172 | if ((tree.getRoot() == null) && (getSpatialFiltersCount() == 0)){ |
||
173 | return null; |
||
174 | } |
||
175 | if (tree.getRoot() != null){ |
||
176 | currentQuery = new StringBuffer(); |
||
177 | filterQuery = getFilterNode(tree.getRoot()); |
||
178 | if (getSpatialFiltersCount() == 0){ |
||
179 | return enclosesWithFilterTag(filterQuery);
|
||
180 | } |
||
181 | } |
||
182 | //If is a filter by area
|
||
183 | String bboxQuery = null; |
||
184 | if (getSpatialFiltersCount() > 0){ |
||
185 | for (int i=0 ; i<getSpatialFiltersCount() ; i++){ |
||
186 | WFSSpatialFilterOperation spatialFilter = getSpatialFilterAt(i); |
||
187 | SpatialFEQuery feQuery = null;
|
||
188 | if (spatialFilter instanceof WFSGeometryFilterOperation){ |
||
189 | feQuery = new GeometryFEQuery((WFSGeometryFilterOperation)spatialFilter);
|
||
190 | }else if (spatialFilter instanceof WFSEnvelopeFilterOperation){ |
||
191 | //TODO add this for a manager
|
||
192 | if (version.equals("1.0.0")){ |
||
193 | feQuery = new EnvelopeFEQuery1_0_0((WFSEnvelopeFilterOperation)spatialFilter);
|
||
194 | }else{
|
||
195 | feQuery = new EnvelopeFEQuery1_1_0((WFSEnvelopeFilterOperation)spatialFilter);
|
||
196 | } |
||
197 | } |
||
198 | //If there is a spatial query
|
||
199 | if (feQuery != null){ |
||
200 | bboxQuery = feQuery.getFilterEncoding(); |
||
201 | if (tree.getRoot() == null){ |
||
202 | String filter_bbox = enclosesWithFilterTag(bboxQuery);
|
||
203 | return filter_bbox;
|
||
204 | } |
||
205 | } |
||
206 | } |
||
207 | } |
||
208 | return enclosesWithFilterTag(filterQuery + bboxQuery);
|
||
209 | } |
||
210 | |||
211 | /**
|
||
212 | * Gets the filter code from a node
|
||
213 | * @param node
|
||
214 | */
|
||
215 | private String getFilterNode(Node node){ |
||
216 | if (node.isField()){
|
||
217 | return getExpression(node.getValue());
|
||
218 | }else{
|
||
219 | String left = ""; |
||
220 | String rigth = ""; |
||
221 | if (node.getLeftNode() != null){ |
||
222 | left = getFilterNode(node.getLeftNode()); |
||
223 | } |
||
224 | if (node.getRigthNode() != null){ |
||
225 | rigth = getFilterNode(node.getRigthNode()); |
||
226 | } |
||
227 | int operationCode = getLogicalOperator(node.getValue());
|
||
228 | String operation = getLogicalOperator(operationCode);
|
||
229 | return enterLabel(left+rigth, operation);
|
||
230 | } |
||
231 | } |
||
232 | |||
233 | /**
|
||
234 | * Parses a expresion like 'A op B' and returns the
|
||
235 | * expresion using the filter encoding language
|
||
236 | * @param expression
|
||
237 | * @return
|
||
238 | */
|
||
239 | private String getExpression(String expression){ |
||
240 | String[] words = stringUtils.split(expression, " "); |
||
241 | //Param
|
||
242 | String param = words[0]; |
||
243 | if (param.charAt(0) == '"'){ |
||
244 | param = param.substring(1,param.length());
|
||
245 | } |
||
246 | if (param.charAt(param.length()-1) == '"'){ |
||
247 | param = param.substring(0,param.length()-1); |
||
248 | } |
||
249 | //Operator
|
||
250 | String operator = words[1]; |
||
251 | //Value
|
||
252 | String value = words[2]; |
||
253 | for (int i=3 ; i<words.length ; i++){ |
||
254 | value = value + " " + words[i];
|
||
255 | } |
||
256 | if (value.charAt(0) == '\''){ |
||
257 | value = value.substring(1,value.length());
|
||
258 | } |
||
259 | if (value.charAt(value.length()-1) == '\''){ |
||
260 | value = value.substring(0,value.length()-1); |
||
261 | } |
||
262 | int operatorCode = getRelationalOperator(operator);
|
||
263 | operator = getRelationalOperator(operatorCode); |
||
264 | return createExpression(operator,param,value);
|
||
265 | } |
||
266 | |||
267 | /**
|
||
268 | * It writes a "PropertyIsXXX" part of a filtyer encoding query
|
||
269 | *
|
||
270 | *
|
||
271 | * @return The part of the query
|
||
272 | * @param property Possible Values: PropertIsLike, PropertyIsLess, PropertyIsGreater,... See
|
||
273 | * the Filter Encoding documentation
|
||
274 | * @param parameter Parameter name
|
||
275 | * @param value Parameter value
|
||
276 | * @param type Values: "P" (to comparate two propertyes) or "L" (to comparate one property
|
||
277 | * and one literal value)
|
||
278 | */
|
||
279 | private String createExpression(String property, String parameter, String value) { |
||
280 | String cadena = ""; |
||
281 | cadena = "<" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property; |
||
282 | if (property.equals("PropertyIsLike")) { |
||
283 | if (wildCardChar != null) { |
||
284 | cadena = cadena + " wildCard=\"" + this.wildCardChar + "\""; |
||
285 | } |
||
286 | if (singleChar != null) { |
||
287 | cadena = cadena + " singleChar=\"" + this.singleChar + "\""; |
||
288 | } |
||
289 | if (escapeChar != null) { |
||
290 | cadena = cadena + " escape=\"" + this.escapeChar + "\""; |
||
291 | } |
||
292 | } |
||
293 | cadena = cadena + ">" + enterLabel(nameSpacePrefix + ":" + parameter, "PropertyName"); |
||
294 | cadena = cadena + enterLabel(value, "Literal");
|
||
295 | return cadena + "</" + WFSTTags.OGC_NAMESPACE_PREFIX + ":" + property + ">"; |
||
296 | } |
||
297 | |||
298 | /**
|
||
299 | * Envuelve a una pregunta con una etiqueta
|
||
300 | *
|
||
301 | *
|
||
302 | * @return String : parte de la query en el lenguaje soportado
|
||
303 | * @param pregunta Pregunta a envolver
|
||
304 | * @param etiqueta Nombre de la etiqueta
|
||
305 | */
|
||
306 | private String enterLabel(String value, String tagName) { |
||
307 | if (tagName.equals("Filter") && (!(filterAttributes.isEmpty()))) { |
||
308 | return setTag(tagName,filterAttributes,value);
|
||
309 | } else {
|
||
310 | return setTag(tagName,null,value); |
||
311 | } |
||
312 | } |
||
313 | |||
314 | /**
|
||
315 | * Envolves a value with an XML tag
|
||
316 | *
|
||
317 | * @return String
|
||
318 | * XML tag with its value
|
||
319 | * @param tagName
|
||
320 | * XML tag name
|
||
321 | * @param attributes
|
||
322 | * XML tag attributes
|
||
323 | * @param value
|
||
324 | * Tag value
|
||
325 | */
|
||
326 | public String setTag(String tagName, Hashtable attributes, String value) { |
||
327 | StringBuffer tag = new StringBuffer(); |
||
328 | |||
329 | tag.append("<");
|
||
330 | tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
|
||
331 | tag.append(tagName); |
||
332 | if (attributes != null){ |
||
333 | Set keys = attributes.keySet();
|
||
334 | if (attributes.size() > 0){ |
||
335 | Iterator it = keys.iterator();
|
||
336 | while (it.hasNext()){
|
||
337 | String key = (String)it.next(); |
||
338 | if (hasBlankSpaces){
|
||
339 | tag.append(" ");
|
||
340 | }else{
|
||
341 | tag.append(defaultBlankSpace); |
||
342 | } |
||
343 | tag.append(key + "=" + (String)attributes.get(key)); |
||
344 | |||
345 | } |
||
346 | } |
||
347 | } |
||
348 | if (value == null){ |
||
349 | tag.append("/>");
|
||
350 | }else{
|
||
351 | tag.append(">" + value);
|
||
352 | tag.append("</");
|
||
353 | tag.append(WFSTTags.OGC_NAMESPACE_PREFIX + ":");
|
||
354 | tag.append(tagName); |
||
355 | tag.append(">");
|
||
356 | } |
||
357 | return tag.toString();
|
||
358 | } |
||
359 | |||
360 | |||
361 | /**
|
||
362 | * Encloses a query with the filter tag
|
||
363 | * @param query
|
||
364 | * @return
|
||
365 | */
|
||
366 | private String enclosesWithFilterTag(String query){ |
||
367 | StringBuffer filter = new StringBuffer(); |
||
368 | filter.append("<ogc:Filter");
|
||
369 | if (!isQualified){
|
||
370 | filter.append(" ");
|
||
371 | addNamespace(filter, WFSTTags.OGC_NAMESPACE_PREFIX, WFSTTags.OGC_NAMESPACE); |
||
372 | addNamespace(filter, WFSTTags.GML_NAMESPACE_PREFIX, WFSTTags.GML_NAMESPACE); |
||
373 | if (nameSpacePrefix != null){ |
||
374 | addNamespace(filter, nameSpacePrefix, nameSpaceLocation); |
||
375 | } |
||
376 | filter.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
|
||
377 | filter.append("xsi:schemaLocation=\"http://www.opengis.net/ogc ../filter/1.0.0/filter.xsd http://www.opengis.net/gml ../gml/2.1.2/geometry.xsd\"");
|
||
378 | } |
||
379 | filter.append(">");
|
||
380 | filter.append(query); |
||
381 | filter.append("</ogc:Filter>");
|
||
382 | return filter.toString();
|
||
383 | } |
||
384 | |||
385 | private void addNamespace(StringBuffer buffer, String nameSpacePrefix, String nameSpaceLocation){ |
||
386 | buffer.append(WFSTTags.XMLNS + ":" + nameSpacePrefix + "=\"" + nameSpaceLocation + "\" "); |
||
387 | } |
||
388 | |||
389 | /*
|
||
390 | * (non-Javadoc)
|
||
391 | * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getLogicOperator(int)
|
||
392 | */
|
||
393 | public String getLogicalOperator(int operator) { |
||
394 | switch (operator){
|
||
395 | case LOGICAL_OPERATOR_AND:
|
||
396 | return "And"; |
||
397 | case LOGICAL_OPERATOR_OR:
|
||
398 | return "Or"; |
||
399 | case LOGICAL_OPERATOR_NOT:
|
||
400 | return "Not"; |
||
401 | default:
|
||
402 | return "And"; |
||
403 | } |
||
404 | } |
||
405 | |||
406 | /*
|
||
407 | * (non-Javadoc)
|
||
408 | * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getRelationalOperator(int)
|
||
409 | */
|
||
410 | public String getRelationalOperator(int operator) { |
||
411 | switch (operator){
|
||
412 | case RELATIONAL_OPERATOR_IS_EQUALS_TO:
|
||
413 | return "PropertyIsEqualTo"; |
||
414 | case RELATIONAL_OPERATOR_IS_NOT_EQUALS_TO:
|
||
415 | return "PropertyIsNotEqualTo"; |
||
416 | case RELATIONAL_OPERATOR_IS_LESS_THAN:
|
||
417 | return "PropertyIsLessThan"; |
||
418 | case RELATIONAL_OPERATOR_IS_GREATER_THAN:
|
||
419 | return "PropertyIsGreaterThan"; |
||
420 | case RELATIONAL_OPERATOR_IS_LESS_THAN_OR_EQUAL_TO:
|
||
421 | return "PropertyIsLessThanOrEqualTo"; |
||
422 | case RELATIONAL_OPERATOR_IS_GREATER_THAN_OR_EQUAL_TO:
|
||
423 | return "PropertyIsGreaterThanOrEqualTo"; |
||
424 | case RELATIONAL_OPERATOR_IS_LIKE:
|
||
425 | return "PropertyIsLike"; |
||
426 | case RELATIONAL_OPERATOR_IS_NULL:
|
||
427 | return "PropertyIsNull"; |
||
428 | case RELATIONAL_OPERATOR_IS_BETWEEN:
|
||
429 | return "PropertyIsBetween"; |
||
430 | default:
|
||
431 | return "PropertyIsLike"; |
||
432 | } |
||
433 | } |
||
434 | |||
435 | /*
|
||
436 | * (non-Javadoc)
|
||
437 | * @see org.gvsig.remoteClient.filterEncoding.AQueryLanguage#getGeometricOperator(int)
|
||
438 | */
|
||
439 | public String getGeometricOperator(int operator) { |
||
440 | switch (operator){
|
||
441 | case GEOMETRIC_OPERATOR_EQUALS:
|
||
442 | return "Equals"; |
||
443 | case GEOMETRIC_OPERATOR_DISJOINT:
|
||
444 | return "Disjoint"; |
||
445 | case GEOMETRIC_OPERATOR_TOUCHES:
|
||
446 | return "Touches"; |
||
447 | case GEOMETRIC_OPERATOR_WITHIN:
|
||
448 | return "Within"; |
||
449 | case GEOMETRIC_OPERATOR_OVERLAPS:
|
||
450 | return "Overlaps"; |
||
451 | case GEOMETRIC_OPERATOR_CROSSES:
|
||
452 | return "Crosses"; |
||
453 | case GEOMETRIC_OPERATOR_INTERSECT:
|
||
454 | return "Intersect"; |
||
455 | case GEOMETRIC_OPERATOR_CONTAINS:
|
||
456 | return "Contains"; |
||
457 | case GEOMETRIC_OPERATOR_DWITHIN:
|
||
458 | return "Dwithin"; |
||
459 | case GEOMETRIC_OPERATOR_BEYOND:
|
||
460 | return "Beyond"; |
||
461 | case GEOMETRIC_OPERATOR_BBOX:
|
||
462 | return "BBOX"; |
||
463 | default:
|
||
464 | return "Equals"; |
||
465 | } |
||
466 | |||
467 | } |
||
468 | |||
469 | public String getSeparator(int separator) { |
||
470 | return null; |
||
471 | } |
||
472 | |||
473 | /**
|
||
474 | * @param isQualified the isQualified to set
|
||
475 | */
|
||
476 | public void setQualified(boolean isQualified) { |
||
477 | this.isQualified = isQualified;
|
||
478 | if (isQualified){
|
||
479 | nameSpacePrefix = DEFAULT_NAMESPACE_PREFIX + ":";
|
||
480 | }else{
|
||
481 | nameSpacePrefix = "";
|
||
482 | } |
||
483 | } |
||
484 | |||
485 | |||
486 | /**
|
||
487 | * @param namepacePrefix the namepacePrefix to set
|
||
488 | */
|
||
489 | public void setNamepacePrefix(String namepacePrefix) { |
||
490 | if ((namepacePrefix == null) || (namepacePrefix.equals(""))){ |
||
491 | this.nameSpacePrefix = ""; |
||
492 | }else{
|
||
493 | this.nameSpacePrefix = namepacePrefix + ":"; |
||
494 | } |
||
495 | } |
||
496 | |||
497 | |||
498 | /**
|
||
499 | * @param hasBlankSpaces the hasBlankSpaces to set
|
||
500 | */
|
||
501 | public void setHasBlankSpaces(boolean hasBlankSpaces) { |
||
502 | this.hasBlankSpaces = hasBlankSpaces;
|
||
503 | } |
||
504 | } |