Project

General

Profile

Download (49.8 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy 
4
* http://www.e-taxonomy.eu
5
* 
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.io.markup;
11

    
12
import java.util.Arrays;
13
import java.util.Collection;
14
import java.util.HashMap;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Stack;
19
import java.util.UUID;
20

    
21
import javax.xml.namespace.QName;
22
import javax.xml.stream.Location;
23
import javax.xml.stream.XMLEventReader;
24
import javax.xml.stream.XMLStreamConstants;
25
import javax.xml.stream.XMLStreamException;
26
import javax.xml.stream.events.Attribute;
27
import javax.xml.stream.events.Characters;
28
import javax.xml.stream.events.EndElement;
29
import javax.xml.stream.events.StartElement;
30
import javax.xml.stream.events.XMLEvent;
31

    
32
import org.apache.commons.lang.StringUtils;
33
import org.apache.commons.lang.WordUtils;
34
import org.apache.log4j.Logger;
35

    
36
import eu.etaxonomy.cdm.api.service.IClassificationService;
37
import eu.etaxonomy.cdm.api.service.ITermService;
38
import eu.etaxonomy.cdm.common.CdmUtils;
39
import eu.etaxonomy.cdm.ext.geo.GeoServiceArea;
40
import eu.etaxonomy.cdm.ext.geo.IEditGeoService;
41
import eu.etaxonomy.cdm.io.common.CdmImportBase;
42
import eu.etaxonomy.cdm.io.common.CdmImportBase.TermMatchMode;
43
import eu.etaxonomy.cdm.io.common.events.IIoEvent;
44
import eu.etaxonomy.cdm.io.common.events.IoProblemEvent;
45
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
46
import eu.etaxonomy.cdm.model.agent.Team;
47
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
48
import eu.etaxonomy.cdm.model.common.AnnotationType;
49
import eu.etaxonomy.cdm.model.common.CdmBase;
50
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
51
import eu.etaxonomy.cdm.model.common.ExtensionType;
52
import eu.etaxonomy.cdm.model.common.Language;
53
import eu.etaxonomy.cdm.model.common.TermVocabulary;
54
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
55
import eu.etaxonomy.cdm.model.description.Feature;
56
import eu.etaxonomy.cdm.model.description.PolytomousKey;
57
import eu.etaxonomy.cdm.model.description.TaxonDescription;
58
import eu.etaxonomy.cdm.model.location.NamedArea;
59
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
60
import eu.etaxonomy.cdm.model.location.NamedAreaType;
61
import eu.etaxonomy.cdm.model.media.Media;
62
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
63
import eu.etaxonomy.cdm.model.name.NonViralName;
64
import eu.etaxonomy.cdm.model.name.Rank;
65
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
66
import eu.etaxonomy.cdm.model.reference.Reference;
67
import eu.etaxonomy.cdm.model.taxon.Classification;
68
import eu.etaxonomy.cdm.model.taxon.Taxon;
69
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
70
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
71

    
72
/**
73
 * @author a.mueller
74
 * @created 04.08.2008
75
 */
76
public abstract class MarkupImportBase  {
77
	@SuppressWarnings("unused")
78
	private static final Logger logger = Logger.getLogger(MarkupImportBase.class);
79

    
80
	//Base
81
	protected static final String ALTITUDE = "altitude";
82
	protected static final String ANNOTATION = "annotation";
83
	protected static final String BOLD = "bold";
84
	protected static final String BR = "br";
85
	protected static final String CITATION = "citation";
86
	protected static final String CLASS = "class";
87
	protected static final String COORDINATES = "coordinates";
88
	protected static final String DATES = "dates";
89
	protected static final String GATHERING = "gathering";
90
	protected static final String GENUS_ABBREVIATION = "genus abbreviation";
91
	protected static final String FOOTNOTE = "footnote";
92
	protected static final String FOOTNOTE_REF = "footnoteRef";
93
	protected static final String FULL_NAME = "fullName";
94
	protected static final String ITALICS = "italics";
95
	protected static final String NUM = "num";
96
	protected static final String NOTES = "notes";
97
	protected static final String PUBLICATION = "publication";
98
	protected static final String SPECIMEN_TYPE = "specimenType";
99
	protected static final String STATUS = "status";
100
	protected static final String SUB_HEADING = "subHeading";
101
	protected static final String TYPE = "type";
102
	protected static final String TYPE_STATUS = "typeStatus";
103

    
104
	protected static final boolean CREATE_NEW = true;
105
	protected static final boolean NO_IMAGE_GALLERY = false;
106
	protected static final boolean IMAGE_GALLERY = true;
107

    
108
	protected static final String ADDENDA = "addenda";
109
	protected static final String BIBLIOGRAPHY = "bibliography";
110
	protected static final String BIOGRAPHIES = "biographies";
111
	protected static final String CHAR = "char";
112
	protected static final String DEDICATION = "dedication";
113
	protected static final String DEFAULT_MEDIA_URL = "defaultMediaUrl";
114
	protected static final String DISTRIBUTION_LIST = "distributionList";
115
	protected static final String DISTRIBUTION_LOCALITY = "distributionLocality";
116
	protected static final String FEATURE = "feature";
117
	protected static final String FIGURE = "figure";
118
	protected static final String FIGURE_LEGEND = "figureLegend";
119
	protected static final String FIGURE_PART = "figurePart";
120
	protected static final String FIGURE_REF = "figureRef";
121
	protected static final String FIGURE_TITLE = "figureTitle";
122
	protected static final String FOOTNOTE_STRING = "footnoteString";
123
	protected static final String FREQUENCY = "frequency";
124
	protected static final String HEADING = "heading";
125
	protected static final String HABITAT = "habitat";
126
	protected static final String HABITAT_LIST = "habitatList";
127
	protected static final String IS_FREETEXT = "isFreetext";
128
	protected static final String ID = "id";
129
	protected static final String KEY = "key";
130
	protected static final String LIFE_CYCLE_PERIODS = "lifeCyclePeriods";
131
	protected static final String META_DATA = "metaData";
132
	protected static final String MODS = "mods";
133

    
134
	protected static final String NOMENCLATURE = "nomenclature";
135
	protected static final String QUOTE = "quote";
136
	protected static final String RANK = "rank";
137
	protected static final String REF = "ref";
138
	protected static final String REF_NUM = "refNum";
139
	protected static final String REFERENCE = "reference";
140
	protected static final String REFERENCES = "references";
141
	protected static final String SUB_CHAR = "subChar";
142
	protected static final String TAXON = "taxon";
143
	protected static final String TAXONTITLE = "taxontitle";
144
	protected static final String TAXONTYPE = "taxontype";
145
	protected static final String TEXT_SECTION = "textSection";
146
	protected static final String TREATMENT = "treatment";
147
	protected static final String SERIALS_ABBREVIATIONS = "serialsAbbreviations";
148
	protected static final String STRING = "string";
149
	protected static final String URL = "url";
150
	protected static final String VERNACULAR_NAMES = "vernacularNames";
151
	protected static final String WRITER = "writer";
152
	
153
	
154
	//Nomenclature
155
	protected static final String ACCEPTED = "accepted";
156
	protected static final String ACCEPTED_NAME = "acceptedName";
157
	protected static final String ALTERNATEPUBTITLE = "alternatepubtitle";
158
	protected static final String AUTHOR = "author";
159
	protected static final String DETAILS = "details";
160
	protected static final String EDITION = "edition";
161
	protected static final String EDITORS = "editors";
162
	protected static final String HOMONYM = "homonym";
163
	protected static final String HOMOTYPES = "homotypes";
164
	protected static final String INFRANK = "infrank";
165
	protected static final String INFRAUT = "infraut";
166
	protected static final String INFRPARAUT = "infrparaut";
167
	protected static final String ISSUE = "issue";
168
	protected static final String NAME = "name";
169
	protected static final String NAME_TYPE = "nameType";
170
	protected static final String NOM = "nom";
171
	protected static final String PAGES = "pages";
172
	protected static final String PARAUT = "paraut";
173
	protected static final String PUBFULLNAME = "pubfullname";
174
	protected static final String PUBNAME = "pubname";
175
	protected static final String PUBTITLE = "pubtitle";
176
	protected static final String PUBTYPE = "pubtype";
177
	protected static final String REF_PART = "refPart";
178
	protected static final String SYNONYM = "synonym";
179
	protected static final String USAGE = "usage";
180
	protected static final String VOLUME = "volume";
181
	protected static final String YEAR = "year";
182

    
183
	
184
	//keys
185
	protected static final String COUPLET = "couplet";
186
	protected static final String IS_SPOTCHARACTERS = "isSpotcharacters";
187
	protected static final String ONLY_NUMBERED_TAXA_EXIST = "onlyNumberedTaxaExist";
188
	protected static final String EXISTS = "exists";
189
	protected static final String KEYNOTES = "keynotes";
190
	protected static final String KEY_TITLE = "keyTitle";
191
	protected static final String QUESTION = "question";
192
	protected static final String TEXT = "text";
193
	protected static final String TO_COUPLET = "toCouplet";
194
	protected static final String TO_KEY = "toKey";
195
	protected static final String TO_TAXON = "toTaxon";
196

    
197

    
198
	protected MarkupDocumentImport docImport;
199
	private IEditGeoService editGeoService;
200
	
201
	public MarkupImportBase(MarkupDocumentImport docImport) {
202
		super();
203
		this.docImport = docImport;
204
		this.editGeoService = docImport.getEditGeoService();
205
	}
206

    
207
	private Stack<QName> unhandledElements = new Stack<QName>();
208
	private Stack<QName> handledElements = new Stack<QName>();
209

    
210

    
211
	protected <T extends CdmBase> void  save(Collection<T> collection, MarkupImportState state) {
212
		if (state.isCheck() || collection.isEmpty()){
213
			return;
214
		}
215
		T example = collection.iterator().next();
216
		if (example.isInstanceOf(TaxonBase.class)){
217
			Collection<TaxonBase> typedCollection = (Collection<TaxonBase>)collection;
218
			docImport.getTaxonService().saveOrUpdate(typedCollection);
219
		}else if (example.isInstanceOf(Classification.class)){
220
			Collection<Classification> typedCollection = (Collection<Classification>)collection;
221
			docImport.getClassificationService().saveOrUpdate(typedCollection);
222
		}else if (example.isInstanceOf(PolytomousKey.class)){
223
			Collection<PolytomousKey> typedCollection = (Collection<PolytomousKey>)collection;
224
			docImport.getPolytomousKeyService().saveOrUpdate(typedCollection);
225
		}else if (example.isInstanceOf(DefinedTermBase.class)){
226
			Collection<DefinedTermBase> typedCollection = (Collection<DefinedTermBase>)collection;
227
			getTermService().saveOrUpdate(typedCollection);
228
		}
229
		
230
	}
231
	
232

    
233

    
234
	//TODO move to service layer for all IdentifiableEntities	
235
	protected void save(CdmBase cdmBase, MarkupImportState state) {
236
		if (state.isCheck()){
237
			return;
238
		}
239
		cdmBase = CdmBase.deproxy(cdmBase, CdmBase.class);
240
		if (cdmBase == null){
241
			String message = "Tried to save a null object.";
242
			fireWarningEvent(message, "--location ?? --", 6,1);
243
		} else if (cdmBase.isInstanceOf(TaxonBase.class)){
244
			docImport.getTaxonService().saveOrUpdate((TaxonBase<?>)cdmBase);
245
		}else if (cdmBase.isInstanceOf(Classification.class)){
246
			docImport.getClassificationService().saveOrUpdate((Classification)cdmBase);
247
		}else if (cdmBase.isInstanceOf(PolytomousKey.class)){
248
			docImport.getPolytomousKeyService().saveOrUpdate((PolytomousKey)cdmBase);
249
		}else if (cdmBase.isInstanceOf(DefinedTermBase.class)){
250
			docImport.getTermService().saveOrUpdate((DefinedTermBase<?>)cdmBase);
251
		}else if (cdmBase.isInstanceOf(Media.class)){
252
			docImport.getMediaService().saveOrUpdate((Media)cdmBase);
253
		}else if (cdmBase.isInstanceOf(SpecimenOrObservationBase.class)){
254
			docImport.getOccurrenceService().saveOrUpdate((SpecimenOrObservationBase<?>)cdmBase);
255
		}else if (cdmBase.isInstanceOf(DescriptionElementBase.class)){
256
			docImport.getDescriptionService().saveDescriptionElement((DescriptionElementBase)cdmBase);
257
		}else{
258
			String message = "Unknown cdmBase type to save: " + cdmBase.getClass();
259
			fireWarningEvent(message, "Unknown location", 8);
260
		}
261
		//logger.warn("Saved " +  cdmBase);
262
	}
263
	
264
	
265
	protected ITermService getTermService() {
266
		return docImport.getTermService();
267
	}
268
	
269
	protected IClassificationService getClassificationService() {
270
		return docImport.getClassificationService();
271
	}
272

    
273
//*********************** Attribute methods *************************************/
274

    
275
	/**
276
	 * Returns a map for all attributes of an start element
277
	 * @param event
278
	 * @return
279
	 */
280
	protected Map<String, Attribute> getAttributes(XMLEvent event) {
281
		Map<String, Attribute> result = new HashMap<String, Attribute>();
282
		if (!event.isStartElement()){
283
			fireWarningEvent("Event is not an startElement. Can't check attributes", makeLocationStr(event.getLocation()), 1, 1);
284
			return result;
285
		}
286
		StartElement element = event.asStartElement(); 
287
		Iterator<Attribute> attributes = element.getAttributes();
288
		while (attributes.hasNext()){
289
			Attribute attribute = attributes.next();
290
			//TODO namespaces
291
			result.put(attribute.getName().getLocalPart(), attribute);
292
		}
293
		return result;
294
	}
295

    
296
	/**
297
	 * Throws an unexpected attributes event if the event has any attributes.
298
	 * @param event
299
	 */
300
	protected void checkNoAttributes(Map<String, Attribute> attributes, XMLEvent event) {
301
		String[] exceptions = new String[]{};
302
		handleUnexpectedAttributes(event.getLocation(), attributes, 1, exceptions);
303
	}
304
	
305
	
306
	
307
	/**
308
	 * Throws an unexpected attributes event if the event has any attributes.
309
	 * @param event
310
	 */
311
	protected void checkNoAttributes(XMLEvent event) {
312
		String[] exceptions = new String[]{};
313
		checkNoAttributes(event, 1, exceptions); 
314
	}
315

    
316
	/**
317
	 * Throws an unexpected attributes event if the event has any attributes except those mentioned in "exceptions".
318
	 * @param event
319
	 * @param exceptions
320
	 */
321
	protected void checkNoAttributes(XMLEvent event, int stackDepth, String... exceptions) {
322
		if (! event.isStartElement()){
323
			fireWarningEvent("Event is not an startElement. Can't check attributes", makeLocationStr(event.getLocation()), 1, 1);
324
			return;
325
		}
326
		StartElement startElement = event.asStartElement();
327
		Map<String, Attribute> attributes = getAttributes(startElement);
328
		handleUnexpectedAttributes(startElement.getLocation(), attributes, stackDepth+1, exceptions);
329
	}
330
	
331

    
332
	/**
333
	 * Checks if the given attribute exists and has the given value.
334
	 * If yes, true is returned and the attribute is removed from the attributes map.
335
	 * Otherwise false is returned.
336
	 * @param attributes
337
	 * @param attrName
338
	 * @param value
339
	 * @return <code>true</code> if attribute has given value, <code>false</code> otherwise
340
	 */
341
	protected boolean checkAndRemoveAttributeValue( Map<String, Attribute> attributes, String attrName, String value) {
342
		Attribute attr = attributes.get(attrName);
343
		if (attr == null ||value == null ){
344
			return false;
345
		}else{
346
			if (value.equals(attr.getValue())){
347
				attributes.remove(attrName);
348
				return true;
349
			}else{
350
				return false;
351
			}
352
		}
353
	}
354

    
355

    
356
	/**
357
	 * Returns the value of a given attribute name and removes the attribute from the attributes map. 
358
	 * @param attributes
359
	 * @param attrName
360
	 * @return
361
	 */
362
	protected String getAndRemoveAttributeValue(Map<String, Attribute> attributes, String attrName) {
363
		return getAndRemoveAttributeValue(null, attributes, attrName, false, 1);
364
	}
365
	
366
	/**
367
	 * Returns the value of a boolean attribute with the given name and removes the attribute from the attributes map. 
368
	 * Returns <code>defaultValue</code> if the attribute does not exist. ALso returns <code>defaultValue</code> and throws a warning if the
369
	 * attribute has no boolean value (true, false).
370
	 * @param 
371
	 * @param attributes the 
372
	 * @param attrName the name of the attribute
373
	 * @param defaultValue the default value to return if attribute does not exist or can not be defined
374
	 * @return
375
	 */
376
	protected Boolean getAndRemoveBooleanAttributeValue(XMLEvent event, Map<String, Attribute> attributes, String attrName, Boolean defaultValue) {
377
		String value = getAndRemoveAttributeValue(null, attributes, attrName, false, 1);
378
		Boolean result = defaultValue;
379
		if (value != null){
380
			if (value.equalsIgnoreCase("true")){
381
				result = true;
382
			}else if (value.equalsIgnoreCase("false")){
383
				result = false;
384
			}else{
385
				String message = "Boolean attribute has no boolean value ('true', 'false') but '%s'";
386
				fireWarningEvent(String.format(message, value), makeLocationStr(event.getLocation()), 6, 1);
387
			}
388
		}
389
		return result;
390
	}
391

    
392
	
393
	/**
394
	 * Returns the value of a given attribute name and returns the attribute from the attributes map.
395
	 * Fires a mandatory field is missing event if the attribute does not exist.
396
	 * @param xmlEvent
397
	 * @param attributes
398
	 * @param attrName
399
	 * @return
400
	 */
401
	protected String getAndRemoveRequiredAttributeValue(XMLEvent xmlEvent, Map<String, Attribute> attributes, String attrName) {
402
		return getAndRemoveAttributeValue(xmlEvent, attributes, attrName, true, 1);
403
	}
404
	
405
	/**
406
	 * Returns the value of a given attribute name and returns the attribute from the attributes map.
407
	 * If required is <code>true</code> and the attribute does not exist a mandatory field is missing event is fired.
408
	 * @param xmlEvent
409
	 * @param attributes
410
	 * @param attrName
411
	 * @param isRequired
412
	 * @return
413
	 */
414
	private String getAndRemoveAttributeValue(XMLEvent xmlEvent, Map<String, Attribute> attributes, String attrName, boolean isRequired, int stackDepth) {
415
		Attribute attr = attributes.get(attrName);
416
		if (attr == null ){
417
			if (isRequired){
418
				fireMandatoryElementIsMissing(xmlEvent, attrName, 8, stackDepth+1);
419
			}
420
			return null;
421
		}else{
422
			attributes.remove(attrName);
423
			return attr.getValue();
424
		}
425
	}	
426

    
427
	/**
428
	 * Fires an not yet implemented event if the given attribute exists in attributes.
429
	 * @param attributes
430
	 * @param attrName
431
	 */
432
	protected void handleNotYetImplementedAttribute(Map<String, Attribute>  attributes, String attrName) {
433
		Attribute attr = attributes.get(attrName);
434
		if (attr != null){
435
			attributes.remove(attrName);
436
			QName qName = attr.getName();
437
			fireNotYetImplementedAttribute(attr.getLocation(), qName, 1);
438
		}
439
	}
440

    
441
	/**
442
	 * Fires an unhandled attributes event, if attributes exist in attributes map not covered by the exceptions.
443
	 * No event is fired if the unhandled elements stack is not empty.
444
	 * @param location
445
	 * @param attributes
446
	 * @param exceptions
447
	 */
448
	protected void handleUnexpectedAttributes(Location location,Map<String, Attribute> attributes, String... exceptions) {
449
		handleUnexpectedAttributes(location, attributes, 1, exceptions);
450
	}
451
		
452
	/**
453
	 * see {@link #handleUnexpectedAttributes(Location, Map, String...)}
454
     *
455
	 * @param location
456
	 * @param attributes
457
	 * @param stackDepth the stack trace depth
458
	 * @param exceptions
459
	 */
460
	private void handleUnexpectedAttributes(Location location,Map<String, Attribute> attributes, int stackDepth, String... exceptions) {
461
		if (attributes.size() > 0){
462
			if (this.unhandledElements.size() == 0 ){
463
				boolean hasUnhandledAttributes = false;
464
				for (String key : attributes.keySet()){
465
					boolean isException = false;
466
					for (String exception : exceptions){
467
						if(key.equals(exception)){
468
							isException = true;
469
						}
470
					}
471
					if (!isException){
472
						hasUnhandledAttributes = true;
473
					}
474
				}
475
				if (hasUnhandledAttributes){
476
					fireUnexpectedAttributes(location, attributes, stackDepth+1);
477
				}
478
			}
479
		}
480
	}
481

    
482
	
483
	private void fireUnexpectedAttributes(Location location, Map<String, Attribute> attributes, int stackDepth) {
484
		String attributesString = "";
485
		for (String key : attributes.keySet()){
486
			Attribute attribute = attributes.get(key);
487
			attributesString = CdmUtils.concat(",", attributesString, attribute.getName().getLocalPart() + ":" + attribute.getValue());
488
		}
489
		String message = "Unexpected attributes: %s";
490
		IoProblemEvent event = makeProblemEvent(location, String.format(message, attributesString), 1 , stackDepth +1 );
491
		fire(event);	
492
	}
493
	
494

    
495
	protected void fireUnexpectedAttributeValue(XMLEvent parentEvent, String attrName, String attrValue) {
496
		String message = "Unexpected attribute value %s='%s'";
497
		message = String.format(message, attrName, attrValue);
498
		IoProblemEvent event = makeProblemEvent(parentEvent.getLocation(), message, 1 , 1 );
499
		fire(event);
500
	}
501

    
502
	protected void handleNotYetImplementedAttributeValue(XMLEvent xmlEvent, String attrName, String attrValue) {
503
		String message = "Attribute %s not yet implemented for value '%s'";
504
		message = String.format(message, attrName, attrValue);
505
		IIoEvent event = makeProblemEvent(xmlEvent.getLocation(), message, 1, 1 );
506
		fire(event);		
507
	}
508
	
509
	protected void fireNotYetImplementedAttribute(Location location, QName qName, int stackDepth) {
510
		String message = "Attribute not yet implemented: %s";
511
		IIoEvent event = makeProblemEvent(location, String.format(message, qName.getLocalPart()), 1, stackDepth+1 );
512
		fire(event);		
513
	}
514
	
515

    
516
	
517

    
518
	protected void fireUnexpectedEvent(XMLEvent xmlEvent, int stackDepth) {
519
		Location location = xmlEvent.getLocation();
520
		String message = "Unexpected event: %s";
521
		IIoEvent event = makeProblemEvent(location, String.format(message, xmlEvent.toString()), 2, stackDepth +1);
522
		fire(event);		
523
	}
524

    
525
	protected void fireUnexpectedStartElement(Location location, StartElement startElement, int stackDepth) {
526
		QName qName = startElement.getName();
527
		String message = "Unexpected start element: %s";
528
		IIoEvent event = makeProblemEvent(location, String.format(message, qName.getLocalPart()), 2, stackDepth +1);
529
		fire(event);		
530
	}
531
	
532

    
533
	protected void fireUnexpectedEndElement(Location location, EndElement endElement, int stackDepth) {
534
		QName qName = endElement.getName();
535
		String message = "Unexpected end element: %s";
536
		IIoEvent event = makeProblemEvent(location, String.format(message, qName.getLocalPart()), 16, stackDepth+1);
537
		fire(event);		
538
	}
539
	
540
	protected void fireNotYetImplementedElement(Location location, QName qName, int stackDepth) {
541
		String message = "Element not yet implemented: %s";
542
		IIoEvent event = makeProblemEvent(location, String.format(message, qName.getLocalPart()), 1, stackDepth+1 );
543
		fire(event);		
544
	}
545

    
546
	protected void fireNotYetImplementedCharacters(Location location, Characters chars, int stackDepth) {
547
		String message = "Characters not yet handled: %s";
548
		IIoEvent event = makeProblemEvent(location, String.format(message, chars.getData()), 1, stackDepth+1 );
549
		fire(event);		
550
	}
551

    
552
	/**
553
	 * Creates a problem event.
554
	 * Be aware of the right depths of the stack trace !
555
	 * @param location 
556
	 * @param message
557
	 * @param severity
558
	 * @return
559
	 */
560
	private IoProblemEvent makeProblemEvent(Location location, String message, int severity, int stackDepth) {
561
		stackDepth++;
562
		StackTraceElement[] stackTrace = new Exception().getStackTrace();
563
		int lineNumber = stackTrace[stackDepth].getLineNumber();
564
		String methodName = stackTrace[stackDepth].getMethodName();
565
		String locationStr = makeLocationStr(location);
566
		String className = stackTrace[stackDepth].getClassName();
567
		Class<?> declaringClass;
568
		try {
569
			declaringClass = Class.forName(className);
570
		} catch (ClassNotFoundException e) {
571
			declaringClass = this.getClass();
572
		}
573
		IoProblemEvent event = IoProblemEvent.NewInstance(declaringClass, message, 
574
				locationStr, lineNumber, severity, methodName);
575
		return event;
576
	}
577

    
578
	/**
579
	 * Creates a string from a location
580
	 * @param location
581
	 * @return
582
	 */
583
	protected String makeLocationStr(Location location) {
584
		String locationStr = location == null ? " - no location - " : "l." + location.getLineNumber() + "/c."+ location.getColumnNumber();
585
		return locationStr;
586
	}
587
	
588

    
589
	/**
590
	 * Fires an unexpected element event if the unhandled elements stack is empty.
591
	 * Otherwise adds the element to the stack.
592
	 * @param event
593
	 */
594
	protected void handleUnexpectedStartElement(XMLEvent event) {
595
		handleUnexpectedStartElement(event, 1);
596
	}
597
	
598
	/**
599
	 * Fires an unexpected element event if the unhandled elements stack is empty.
600
	 * Otherwise adds the element to the stack.
601
	 * @param event
602
	 */
603
	protected void handleUnexpectedStartElement(XMLEvent event, int stackDepth) {
604
		QName qName = event.asStartElement().getName();
605
		if (! unhandledElements.empty()){
606
			unhandledElements.push(qName);
607
		}else{
608
			fireUnexpectedStartElement(event.getLocation(), event.asStartElement(), stackDepth + 1);
609
		}	
610
	}
611

    
612
	
613
	protected void handleUnexpectedEndElement(EndElement event) {
614
		handleUnexpectedEndElement(event, 1);
615
	}
616
	
617
	/**
618
	 * Fires an unexpected element event if the event is not the last on the stack.
619
	 * Otherwise removes last stack element.
620
	 * @param event
621
	 */
622
	protected void handleUnexpectedEndElement(EndElement event, int stackDepth) {
623
		QName qName = event.asEndElement().getName();
624
		if (!unhandledElements.isEmpty() && unhandledElements.peek().equals(qName)){
625
			unhandledElements.pop();
626
		}else{
627
			fireUnexpectedEndElement(event.getLocation(), event.asEndElement(), stackDepth + 1);
628
		}
629
	}
630
	
631
	/**
632
	 * 
633
	 * @param endElement
634
	 */
635
	protected void popUnimplemented(EndElement endElement) {
636
		QName qName = endElement.asEndElement().getName();
637
		if (unhandledElements.peek().equals(qName)){
638
			unhandledElements.pop();
639
		}else{
640
			String message = "End element is not last on stack: %s";
641
			message = String.format(message, qName.getLocalPart());
642
			IIoEvent event = makeProblemEvent(endElement.getLocation(), message, 16, 1);
643
			fire(event);
644
		}
645
		
646
	}
647
	
648
	
649
	/**
650
	 * Fires an unexpected element event if the unhandled element stack is empty.
651
	 * @param event
652
	 */
653
	protected void handleUnexpectedElement(XMLEvent event) {
654
		if (event.isStartElement()){
655
			handleUnexpectedStartElement(event);
656
		}else if (event.isEndElement()){
657
			handleUnexpectedEndElement(event.asEndElement());
658
		}else if (event.getEventType() == XMLStreamConstants.COMMENT){
659
			//do nothing
660
		}else if (! unhandledElements.empty()){
661
			//do nothing
662
		}else{
663
			fireUnexpectedEvent(event, 1);
664
		}	
665
	}
666
	
667
	/**
668
	 * Fires an not yet implemented event and adds the element name to the unhandled elements stack.
669
	 * @param event
670
	 */
671
	protected void handleNotYetImplementedCharacters(XMLEvent event) {
672
		Characters chars = event.asCharacters();
673
		fireNotYetImplementedCharacters(event.getLocation(), chars, 1);
674
	}
675

    
676
	/**
677
	 * Fires an not yet implemented event and adds the element name to the unhandled elements stack.
678
	 * @param event
679
	 */
680
	protected void handleNotYetImplementedElement(XMLEvent event) {
681
		QName qName = event.asStartElement().getName();
682
		boolean isTopLevel = unhandledElements.isEmpty();
683
		unhandledElements.push(qName);
684
		if (isTopLevel){
685
			fireNotYetImplementedElement(event.getLocation(), qName, 1);
686
		}
687
	}
688

    
689
	/**
690
	 * Checks if a mandatory text is not empty or null.
691
	 * Returns true if text is given.
692
	 * Fires an mandatory element is missing event otherwise and returns <code>null</code>.
693
	 * @param text
694
	 * @param parentEvent
695
	 * @return
696
	 */
697
	protected boolean checkMandatoryText(String text, XMLEvent parentEvent) {
698
		if (! StringUtils.isNotBlank(text)){
699
			fireMandatoryElementIsMissing(parentEvent, "CData", 4, 1);
700
			return false;
701
		}
702
		return true;
703
	}
704
	
705
	/**
706
	 * Fires an mandatory element is missing event if exists is <code>false</code>.
707
	 * @param hasMandatory
708
	 * @param parentEvent
709
	 * @param string
710
	 */
711
	protected void checkMandatoryElement(boolean exists, StartElement parentEvent, String attrName) {
712
		if (! exists){
713
			fireMandatoryElementIsMissing(parentEvent, attrName, 5, 1);
714
		}
715
	}
716

    
717
	
718
	/**
719
	 * Fires an element is missing event.
720
	 * @param xmlEvent
721
	 * @param string
722
	 * @param severity
723
	 * @param stackDepth
724
	 * @throws IllegalStateException if xmlEvent is not a StartElement and not an Attribute
725
	 */
726
	private void fireMandatoryElementIsMissing(XMLEvent xmlEvent, String missingEventName, int severity, int stackDepth) throws IllegalStateException{
727
		Location location = xmlEvent.getLocation();
728
		String typeName;
729
		QName qName;
730
		if (xmlEvent.isAttribute()){
731
			Attribute attribute = ((Attribute)xmlEvent);
732
			typeName = "attribute";
733
			qName = attribute.getName();
734
		}else if (xmlEvent.isStartElement()){
735
			typeName = "element";
736
			qName = xmlEvent.asStartElement().getName();
737
		}else{
738
			throw new IllegalStateException("mandatory element only allowed for attributes and start tags in " + makeLocationStr(location));
739
		}
740
		String message = "Mandatory %s '%s' is missing in %s";
741
		message = String.format(message, typeName , missingEventName, qName.getLocalPart());
742
		IIoEvent event = makeProblemEvent(location, message, severity, stackDepth +1);
743
		fire(event);		
744
	}
745
	
746

    
747

    
748

    
749
	/**
750
	 * Returns true if the "next" event is the ending tag for the "parent" event.
751
	 * @param next end element to test, must not be null
752
	 * @param parentEvent start element to test
753
	 * @return true if the "next" event is the ending tag for the "parent" event.
754
	 * @throws XMLStreamException
755
	 */
756
	protected boolean isMyEndingElement(XMLEvent next, XMLEvent parentEvent) throws XMLStreamException {
757
		if (! parentEvent.isStartElement()){
758
			String message = "Parent event should be start tag";
759
			fireWarningEvent(message, makeLocationStr(next.getLocation()), 6);
760
			return false;
761
		}
762
		return isEndingElement(next, parentEvent.asStartElement().getName().getLocalPart());
763
	}
764
	
765
	/**
766
	 * Trims the text and removes turns all whitespaces into single empty space.
767
	 * @param text
768
	 * @return
769
	 */
770
	protected String normalize(String text) {
771
		text = StringUtils.trimToEmpty(text);
772
		text = text.replaceAll("\\s+", " ");
773
		return text;
774
	}
775
	
776

    
777

    
778
	/**
779
	 * Removes whitespaces at beginning and end and makes the first letter
780
	 * a capital letter and all other letters small letters.
781
	 * @param value
782
	 * @return
783
	 */
784
	protected String toFirstCapital(String value) {
785
		if (StringUtils.isBlank(value)){
786
			return value;
787
		}else{
788
			String result = "";
789
			value = value.trim();
790
			result += value.trim().substring(0,1).toUpperCase();
791
			if (value.length()>1){
792
				result += value.substring(1).toLowerCase();
793
			}
794
			return result;
795
		}
796
	}
797
	
798
	/**
799
	 * Currently not used.
800
	 * @param str
801
	 * @param allowedNumberOfCharacters
802
	 * @param onlyFirstCapital
803
	 * @return
804
	 */
805
	protected boolean isAbbreviation(String str, int allowedNumberOfCharacters, boolean onlyFirstCapital){
806
		if (isBlank(str)){
807
			return false;
808
		}
809
		str = str.trim();
810
		if (! str.endsWith(".")){
811
			return false;
812
		}
813
		str = str.substring(0, str.length() -1);
814
		if (str.length() > allowedNumberOfCharacters){
815
			return false;
816
		}
817
		final String re = "^\\p{javaUpperCase}\\p{javaLowerCase}*$";
818
		if (str.matches(re)){
819
			return true;
820
		}else{
821
			return false;
822
		}
823
	}
824
	
825
	/**
826
	 * Checks if <code>abbrev</code> is the short form for the genus name (strGenusName).
827
	 * Usually this is the case if <code>abbrev</code> is the first letter (optional with ".") 
828
	 * of strGenusName. But in older floras it may also be the first 2 or 3 letters (optional with dot).
829
	 * However, we allow only a maximum of 2 letters to be anambigous. In cases with 3 letters better 
830
	 * change the original markup data.
831
	 * @param single
832
	 * @param strGenusName
833
	 * @return
834
	 */
835
	protected boolean isGenusAbbrev(String abbrev, String strGenusName) {
836
		if (! abbrev.matches("[A-Z][a-z]?\\.?")) {
837
			return false;
838
		}else if (abbrev.length() == 0 || strGenusName == null || strGenusName.length() == 0){
839
			return false; 
840
		}else{
841
			abbrev = abbrev.replace(".", "");
842
			return strGenusName.startsWith(abbrev);
843
//			boolean result = true;
844
//			for (int i = 0 ; i < abbrev.length(); i++){
845
//				result &= ( abbrev.charAt(i) == strGenusName.charAt(i));
846
//			}
847
//			return result;
848
		}
849
	}
850

    
851
	
852
	/**
853
	 * Checks if all words in the given string start with a capital letter but do not have any further capital letter.
854
	 * @param word the string to be checekd. Usually should be a single word.
855
	 * @return true if the above is the case, false otherwise
856
	 */
857
	protected boolean isFirstCapitalWord(String word) {
858
		if (WordUtils.capitalizeFully(word).equals(word)){
859
			return true;
860
		}else if (WordUtils.capitalizeFully(word,new char[]{'-'}).equals(word)){
861
			//for words like Le-Testui (which is a species epithet)
862
			return true;
863
		}else{
864
			return false;
865
		}
866
	}
867
	
868

    
869
	/**
870
	 * Read next event. Ignore whitespace events.
871
	 * @param reader
872
	 * @return
873
	 * @throws XMLStreamException
874
	 */
875
	protected XMLEvent readNoWhitespace(XMLEventReader reader) throws XMLStreamException {
876
		XMLEvent event = reader.nextEvent();
877
		while (event.isCharacters() && event.asCharacters().isWhiteSpace()){
878
			event = reader.nextEvent();
879
		}
880
		return event;
881
	}
882
	
883
	/**
884
	 * Returns the REQUIRED "class" attribute for a given event and checks that it is the only attribute.
885
	 * @param parentEvent
886
	 * @return
887
	 */
888
	protected String getClassOnlyAttribute(XMLEvent parentEvent) {
889
		return getClassOnlyAttribute(parentEvent, true);
890
	}
891

    
892

    
893
	/**
894
	 * Returns the "class" attribute for a given event and checks that it is the only attribute.
895
	 * @param parentEvent
896
	 * @return
897
	 */
898
	protected String getClassOnlyAttribute(XMLEvent parentEvent, boolean required) {
899
		return getOnlyAttribute(parentEvent, CLASS, required);
900
	}
901
	
902
	/**
903
	 * Returns the value for the only attribute for a given event and checks that it is the only attribute.
904
	 * @param parentEvent
905
	 * @return
906
	 */
907
	protected String getOnlyAttribute(XMLEvent parentEvent, String attrName, boolean required) {
908
		Map<String, Attribute> attributes = getAttributes(parentEvent);
909
		String classValue =getAndRemoveAttributeValue(parentEvent, attributes, attrName, required, 1);
910
		checkNoAttributes(attributes, parentEvent);
911
		return classValue;
912
	}
913
	
914
	
915
	protected void fireWarningEvent(String message, String locationStr, Integer severity, Integer depth) {
916
		docImport.fireWarningEvent(message, locationStr, severity, depth);
917
	}
918
	
919
	protected void fireWarningEvent(String message, XMLEvent event, Integer severity) {
920
		docImport.fireWarningEvent(message, makeLocationStr(event.getLocation()), severity, 1);
921
	}
922
	
923
	protected void fireSchemaConflictEventExpectedStartTag(String elName, XMLEventReader reader) throws XMLStreamException {
924
		docImport.fireSchemaConflictEventExpectedStartTag(elName, reader);
925
	}
926

    
927
	
928
	protected void fireWarningEvent(String message, String locationStr, int severity) {
929
		docImport.fireWarningEvent(message, locationStr, severity, 1);	
930
	}
931
	
932
	protected void fire(IIoEvent event) {
933
		docImport.fire(event);
934
	}
935
	
936
	protected boolean isNotBlank(String str){
937
		return StringUtils.isNotBlank(str);
938
	}
939
	
940
	protected boolean isBlank(String str){
941
		return StringUtils.isBlank(str);
942
	}
943

    
944
	public TaxonDescription getTaxonDescription(Taxon taxon, Reference<?> ref, boolean isImageGallery, boolean createNewIfNotExists) {
945
		return docImport.getTaxonDescription(taxon, isImageGallery, createNewIfNotExists);	
946
	}	
947
	
948

    
949
	/**
950
	 * Returns the default language defined in the state. If no default language is defined in the state,
951
	 * the CDM default language is returned.
952
	 * @param state
953
	 * @return
954
	 */
955
	protected Language getDefaultLanguage(MarkupImportState state) {
956
		Language result = state.getDefaultLanguage();
957
		if (result == null){
958
			result = Language.DEFAULT();
959
		}
960
		return result;
961
	}
962

    
963

    
964
//*********************** FROM XML IMPORT BASE ****************************************
965
	protected boolean isEndingElement(XMLEvent event, String elName) throws XMLStreamException {
966
		return docImport.isEndingElement(event, elName);
967
	}
968
	
969
	protected boolean isStartingElement(XMLEvent event, String elName) throws XMLStreamException {
970
		return docImport.isStartingElement(event, elName);
971
	}
972
	
973

    
974
	protected void fillMissingEpithetsForTaxa(Taxon parentTaxon, Taxon childTaxon) {
975
		docImport.fillMissingEpithetsForTaxa(parentTaxon, childTaxon);	
976
	}
977
	
978
	protected Feature getFeature(MarkupImportState state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<Feature> voc){
979
		return docImport.getFeature(state, uuid, label, text, labelAbbrev, voc);
980
	}
981
	
982
	protected ExtensionType getExtensionType(MarkupImportState state, UUID uuid, String label, String text, String labelAbbrev){
983
		return docImport.getExtensionType(state, uuid, label, text, labelAbbrev);
984
	}
985
	
986
	protected AnnotationType getAnnotationType(MarkupImportState state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<AnnotationType> voc){
987
		return docImport.getAnnotationType(state, uuid, label, text, labelAbbrev, voc);
988
	}
989
	
990
	protected NamedAreaLevel getNamedAreaLevel(MarkupImportState state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<NamedAreaLevel> voc){
991
		return docImport.getNamedAreaLevel(state, uuid, label, text, labelAbbrev, voc);
992
	}
993
	
994
	protected NamedArea getNamedArea(MarkupImportState state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc, TermMatchMode matchMode){
995
		return docImport.getNamedArea(state, uuid, label, text, labelAbbrev, areaType, level, voc, matchMode);
996
	}
997
	
998
	protected Language getLanguage(MarkupImportState state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<?> voc){
999
		return docImport.getLanguage(state, uuid, label, text, labelAbbrev, voc);
1000
	}
1001
	
1002
// *************************************** Concrete methods **********************************************/
1003

    
1004

    
1005
	/**
1006
	 * @param state
1007
	 * @param classValue
1008
	 * @param byAbbrev
1009
	 * @return
1010
	 */
1011
	protected Rank makeRank(MarkupImportState state, String value, boolean byAbbrev) {
1012
		Rank rank = null;
1013
		if (StringUtils.isBlank(value)) {
1014
			return null;
1015
		}
1016
		try {
1017
			boolean useUnknown = true;
1018
			NomenclaturalCode nc = makeNomenclaturalCode(state);
1019
			if (value.equals(GENUS_ABBREVIATION)){
1020
				rank = Rank.GENUS();
1021
			}else if (byAbbrev) {
1022
				rank = Rank.getRankByAbbreviation(value, nc, useUnknown);
1023
			} else {
1024
				rank = Rank.getRankByEnglishName(value, nc, useUnknown);
1025
			}
1026
			if (rank.equals(Rank.UNKNOWN_RANK())) {
1027
				rank = null;
1028
			}
1029
		} catch (UnknownCdmTypeException e) {
1030
			// doNothing
1031
		}
1032
		return rank;
1033
	}
1034

    
1035

    
1036

    
1037
	protected TeamOrPersonBase<?> createAuthor(String authorTitle) {
1038
		// TODO atomize and also use by name creation
1039
		TeamOrPersonBase<?> result = Team.NewTitledInstance(authorTitle, authorTitle);
1040
		return result;
1041
	}
1042
	
1043
	protected String getAndRemoveMapKey(Map<String, String> map, String key) {
1044
		String result = map.get(key);
1045
		map.remove(key);
1046
		if (result != null) {
1047
			result = normalize(result);
1048
		}
1049
		return StringUtils.stripToNull(result);
1050
	}
1051

    
1052

    
1053
	/**
1054
	 * Creates a {@link NonViralName} object depending on the defined {@link NomenclaturalCode}
1055
	 * and the given parameters.
1056
	 * @param state
1057
	 * @param rank
1058
	 * @return
1059
	 */
1060
	protected NonViralName<?> createNameByCode(MarkupImportState state, Rank rank) {
1061
		NonViralName<?> name;
1062
		NomenclaturalCode nc = makeNomenclaturalCode(state);
1063
		name = (NonViralName<?>) nc.getNewTaxonNameInstance(rank);
1064
		return name;
1065
	}
1066
	
1067

    
1068
	/**
1069
	 * Returns the {@link NomenclaturalCode} for this import. Default is {@link NomenclaturalCode#ICBN} if
1070
	 * no code is defined.
1071
	 * @param state
1072
	 * @return
1073
	 */
1074
	protected NomenclaturalCode makeNomenclaturalCode(MarkupImportState state) {
1075
		NomenclaturalCode nc = state.getConfig().getNomenclaturalCode();
1076
		if (nc == null) {
1077
			nc = NomenclaturalCode.ICBN; // default;
1078
		}
1079
		return nc;
1080
	}
1081

    
1082

    
1083
	/**
1084
	 * @param state
1085
	 * @param levelString
1086
	 * @param next
1087
	 * @return
1088
	 */
1089
	protected NamedAreaLevel makeNamedAreaLevel(MarkupImportState state, String levelString, XMLEvent next) {
1090
		NamedAreaLevel level;
1091
		try {
1092
			level = state.getTransformer().getNamedAreaLevelByKey(levelString);
1093
			if (level == null) {
1094
				UUID levelUuid = state.getTransformer().getNamedAreaLevelUuid(levelString);
1095
				if (levelUuid == null) {
1096
					String message = "Unknown distribution locality class (named area level): %s. Create new level instead.";
1097
					message = String.format(message, levelString);
1098
					fireWarningEvent(message, next, 6);
1099
				}
1100
				level = getNamedAreaLevel(state, levelUuid, levelString, levelString, levelString, null);
1101
			}
1102
		} catch (UndefinedTransformerMethodException e) {
1103
			throw new RuntimeException(e);
1104
		}
1105
		return level;
1106
	}
1107
	
1108

    
1109
	/**
1110
	 * @param state
1111
	 * @param areaName
1112
	 * @param level
1113
	 * @return 
1114
	 */
1115
	protected NamedArea makeArea(MarkupImportState state, String areaName, NamedAreaLevel level) {
1116
		
1117
		//TODO FM vocabulary
1118
		TermVocabulary<NamedArea> voc = null; 
1119
		NamedAreaType areaType = null;
1120
		
1121
		NamedArea area = null;
1122
		try {
1123
			area = state.getTransformer().getNamedAreaByKey(areaName);
1124
		} catch (UndefinedTransformerMethodException e) {
1125
			throw new RuntimeException(e);
1126
		}
1127
		if (area == null){
1128
			boolean isNewInState = false;
1129
			UUID uuid = state.getAreaUuid(areaName);
1130
			if (uuid == null){
1131
				isNewInState = true;
1132
				
1133
				
1134
				try {
1135
					uuid = state.getTransformer().getNamedAreaUuid(areaName);
1136
				} catch (UndefinedTransformerMethodException e) {
1137
					throw new RuntimeException(e);
1138
				}
1139
			}
1140
			
1141
			CdmImportBase.TermMatchMode matchMode = CdmImportBase.TermMatchMode.UUID_LABEL;
1142
			area = getNamedArea(state, uuid, areaName, areaName, areaName, areaType, level, voc, matchMode);
1143
			if (isNewInState){
1144
				state.putAreaUuid(areaName, area.getUuid());
1145
				
1146
				//TODO just for testing -> make generic and move to better place
1147
				String geoServiceLayer="vmap0_as_bnd_political_boundary_a";
1148
				String layerFieldName ="nam";
1149
				
1150
				if ("Bangka".equals(areaName)){
1151
					String areaValue = "PULAU BANGKA#SUMATERA SELATAN";
1152
					GeoServiceArea geoServiceArea = new GeoServiceArea();
1153
					geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);
1154
					this.editGeoService.setMapping(area, geoServiceArea);
1155
//					save(area, state);
1156
				}
1157
				if ("Luzon".equals(areaName)){
1158
					GeoServiceArea geoServiceArea = new GeoServiceArea();
1159
					
1160
					List<String> list = Arrays.asList("HERMANA MAYOR ISLAND#CENTRAL LUZON",
1161
							"HERMANA MENOR ISLAND#CENTRAL LUZON",
1162
							"CENTRAL LUZON");
1163
					for (String areaValue : list){
1164
						geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);
1165
					}
1166
					
1167
					this.editGeoService.setMapping(area, geoServiceArea);
1168
//					save(area, state);
1169
				}
1170
				if ("Mindanao".equals(areaName)){
1171
					GeoServiceArea geoServiceArea = new GeoServiceArea();
1172
					
1173
					List<String> list = Arrays.asList("NORTHERN MINDANAO",
1174
							"SOUTHERN MINDANAO",
1175
							"WESTERN MINDANAO");
1176
					//TODO to be continued
1177
					for (String areaValue : list){
1178
						geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);
1179
					}
1180
					
1181
					this.editGeoService.setMapping(area, geoServiceArea);
1182
//					save(area, state);
1183
				}
1184
				if ("Palawan".equals(areaName)){
1185
					GeoServiceArea geoServiceArea = new GeoServiceArea();
1186
					
1187
					List<String> list = Arrays.asList("PALAWAN#SOUTHERN TAGALOG");
1188
					for (String areaValue : list){
1189
						geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);
1190
					}
1191
					
1192
					this.editGeoService.setMapping(area, geoServiceArea);
1193
//					save(area, state);
1194
				}
1195

    
1196
			}
1197
		}
1198
		return area;
1199
	}
1200

    
1201
	
1202
	
1203
	/**
1204
	 * Reads character data. Any element other than character data or the ending
1205
	 * tag will fire an unexpected element event.
1206
     *
1207
	 * @see #getCData(MarkupImportState, XMLEventReader, XMLEvent, boolean)
1208
	 * @param state
1209
	 * @param reader
1210
	 * @param next
1211
	 * @return
1212
	 * @throws XMLStreamException
1213
	 */
1214
	protected String getCData(MarkupImportState state, XMLEventReader reader, XMLEvent next) throws XMLStreamException {
1215
		return getCData(state, reader, next, true);
1216
	}
1217
		
1218
	/**
1219
	 * Reads character data. Any element other than character data or the ending
1220
	 * tag will fire an unexpected element event.
1221
	 * 
1222
	 * @param state
1223
	 * @param reader
1224
	 * @param next
1225
	 * @param inlineMarkup map for inline markup, this is used for e.g. the locality markup within a subheading
1226
	 * The map will be filled by the markup element name as key. The value may be a String, a CdmBase or any other object.
1227
	 * If null any markup text will be neglected but a warning will be fired if they exist.
1228
	 * @param removeInlineMarkupText if true the markedup text will be removed from the returned String 
1229
	 * @param checkAttributes
1230
	 * @return
1231
	 * @throws XMLStreamException
1232
	 */
1233
	protected String getCData(MarkupImportState state, XMLEventReader reader, XMLEvent parent, /*Map<String, Object> inlineMarkup, *boolean removeInlineMarkupText,*/ boolean checkAttributes) throws XMLStreamException {
1234
		if (checkAttributes){
1235
			checkNoAttributes(parent);
1236
		}
1237

    
1238
		String text = "";
1239
		while (reader.hasNext()) {
1240
			XMLEvent next = readNoWhitespace(reader);
1241
			if (isMyEndingElement(next, parent)) {
1242
				return text;
1243
			} else if (next.isCharacters()) {
1244
				text += next.asCharacters().getData();
1245
			} else if (isStartingElement(next, FOOTNOTE_REF)){
1246
				handleNotYetImplementedElement(next);
1247
//			} else if (isStartingElement(next, LOCALITY)){
1248
//				handleCDataLocality(state, reader, parent);
1249
			} else {
1250
				handleUnexpectedElement(next);
1251
			}
1252
		}
1253
		throw new IllegalStateException("Event has no closing tag");
1254

    
1255
	}
1256
	
1257
//	private void handleCDataLocality(MarkupImportState state, XMLEventReader reader, XMLEvent parent) {
1258
//		checkAndRemoveAttributeValue(attributes, attrName, value)
1259
//		
1260
//	}
1261

    
1262

    
1263

    
1264
	/**
1265
	 * For it returns a pure CData annotation string. This behaviour may change in future. More complex annotations
1266
	 * should be handled differently.
1267
	 * @param state
1268
	 * @param reader
1269
	 * @param parentEvent
1270
	 * @return
1271
	 * @throws XMLStreamException
1272
	 */
1273
	protected String handleSimpleAnnotation(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
1274
		String annotation = getCData(state, reader, parentEvent);
1275
		return annotation;
1276
	}
1277
	
1278
	/**
1279
	 * True if text is single "." oder "," or ";" or ":"
1280
	 * @param text
1281
	 * @return
1282
	 */
1283
	protected boolean isPunctuation(String text) {
1284
		return text == null ? false : text.trim().matches("^[\\.,;:]$");
1285
	}
1286

    
1287

    
1288
	
1289
//********************************************** OLD *************************************	
1290

    
1291
//	protected boolean testAdditionalElements(Element parentElement, List<String> excludeList){
1292
//		boolean result = true;
1293
//		List<Element> list = parentElement.getChildren();
1294
//		for (Element element : list){
1295
//			if (! excludeList.contains(element.getName())){
1296
//				logger.warn("Unknown element (" + element.getName() + ") in parent element (" + parentElement.getName() + ")");
1297
//				result = false;
1298
//			}
1299
//		}
1300
//		return result;
1301
//	}
1302
//	
1303
//	
1304
//	protected <T extends IdentifiableEntity> T makeReferenceType(Element element, Class<? extends T> clazz, MapWrapper<? extends T> objectMap, ResultWrapper<Boolean> success){
1305
//		T result = null;
1306
//		String linkType = element.getAttributeValue("linkType");
1307
//		String ref = element.getAttributeValue("ref");
1308
//		if(ref == null && linkType == null){
1309
//			result = getInstance(clazz);
1310
//			if (result != null){
1311
//				String title = element.getTextNormalize();
1312
//				result.setTitleCache(title, true);
1313
//			}
1314
//		}else if (linkType == null || linkType.equals("local")){
1315
//			//TODO
1316
//			result = objectMap.get(ref);
1317
//			if (result == null){
1318
//				logger.warn("Object (ref = " + ref + ")could not be found in WrapperMap");
1319
//			}
1320
//		}else if(linkType.equals("external")){
1321
//			logger.warn("External link types not yet implemented");
1322
//		}else if(linkType.equals("other")){
1323
//			logger.warn("Other link types not yet implemented");
1324
//		}else{
1325
//			logger.warn("Unknown link type or missing ref");
1326
//		}
1327
//		if (result == null){
1328
//			success.setValue(false);
1329
//		}
1330
//		return result;
1331
//	}
1332
//	
1333
//	
1334
//	protected Reference makeAccordingTo(Element elAccordingTo, MapWrapper<Reference> referenceMap, ResultWrapper<Boolean> success){
1335
//		Reference result = null;
1336
//		if (elAccordingTo != null){
1337
//			String childName = "AccordingToDetailed";
1338
//			boolean obligatory = false;
1339
//			Element elAccordingToDetailed = XmlHelp.getSingleChildElement(success, elAccordingTo, childName, elAccordingTo.getNamespace(), obligatory);
1340
//
1341
//			childName = "Simple";
1342
//			obligatory = true;
1343
//			Element elSimple = XmlHelp.getSingleChildElement(success, elAccordingTo, childName, elAccordingTo.getNamespace(), obligatory);
1344
//			
1345
//			if (elAccordingToDetailed != null){
1346
//				result = makeAccordingToDetailed(elAccordingToDetailed, referenceMap, success);
1347
//			}else{
1348
//				result = ReferenceFactory.newGeneric();
1349
//				String title = elSimple.getTextNormalize();
1350
//				result.setTitleCache(title, true);
1351
//			}
1352
//		}
1353
//		return result;
1354
//	}
1355
//	
1356
//	
1357
//	private Reference makeAccordingToDetailed(Element elAccordingToDetailed, MapWrapper<Reference> referenceMap, ResultWrapper<Boolean> success){
1358
//		Reference result = null;
1359
//		Namespace tcsNamespace = elAccordingToDetailed.getNamespace();
1360
//		if (elAccordingToDetailed != null){
1361
//			//AuthorTeam
1362
//			String childName = "AuthorTeam";
1363
//			boolean obligatory = false;
1364
//			Element elAuthorTeam = XmlHelp.getSingleChildElement(success, elAccordingToDetailed, childName, tcsNamespace, obligatory);
1365
//			makeAccordingToAuthorTeam(elAuthorTeam, success);
1366
//			
1367
//			//PublishedIn
1368
//			childName = "PublishedIn";
1369
//			obligatory = false;
1370
//			Element elPublishedIn = XmlHelp.getSingleChildElement(success, elAccordingToDetailed, childName, tcsNamespace, obligatory);
1371
//			result = makeReferenceType(elPublishedIn, Reference.class, referenceMap, success);
1372
//			
1373
//			//MicroReference
1374
//			childName = "MicroReference";
1375
//			obligatory = false;
1376
//			Element elMicroReference = XmlHelp.getSingleChildElement(success, elAccordingToDetailed, childName, tcsNamespace, obligatory);
1377
//			String microReference = elMicroReference.getTextNormalize();
1378
//			if (CdmUtils.Nz(microReference).equals("")){
1379
//				//TODO
1380
//				logger.warn("MicroReference not yet implemented for AccordingToDetailed");	
1381
//			}
1382
//		}
1383
//		return result;
1384
//	}
1385
//
1386
//	private Team makeAccordingToAuthorTeam(Element elAuthorTeam, ResultWrapper<Boolean> succes){
1387
//		Team result = null;
1388
//		if (elAuthorTeam != null){
1389
//			//TODO
1390
//			logger.warn("AuthorTeam not yet implemented for AccordingToDetailed");
1391
//		}
1392
//		return result;
1393
//	}
1394

    
1395

    
1396

    
1397
}
(8-8/18)