Project

General

Profile

Download (17.5 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.print;
11

    
12
import java.util.ArrayList;
13
import java.util.List;
14
import java.util.Locale;
15
import java.util.UUID;
16

    
17
import org.apache.logging.log4j.LogManager;
18
import org.apache.logging.log4j.Logger;
19
import org.jdom.Document;
20
import org.jdom.Element;
21
import org.jdom.JDOMException;
22
import org.jdom.xpath.XPath;
23

    
24
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
25
import eu.etaxonomy.cdm.print.out.IPublishOutputModule;
26

    
27
/**
28
 * Retrieves all necessary data from an {@link IXMLEntityFactory}.
29
 *
30
 * @author n.hoffmann
31
 * @since Apr 8, 2010
32
 * @version 1.0
33
 */
34
public class XMLHarvester {
35
	private static final Logger logger = LogManager.getLogger(XMLHarvester.class);
36

    
37
	private IXMLEntityFactory factory;
38

    
39
	private PublishConfigurator configurator;
40

    
41
	private List<SimplifiedFeatureNode> simplifiedFeatureTree;
42

    
43
	private IProgressMonitor progressMonitor;
44

    
45
	/**
46
	 *
47
	 * @param configurator
48
	 */
49
	public XMLHarvester(PublishConfigurator configurator){
50
		this.configurator = configurator;
51
		this.progressMonitor = configurator.getProgressMonitor();
52
		this.factory = configurator.getFactory();
53

    
54
		Element featureTreeElement = factory.getFeatureTree(configurator.getFeatureTreeUuid());
55
		createSimplifiedFeatureTree(featureTreeElement);
56
	}
57

    
58
	private void createSimplifiedFeatureTree(Element featureTreeElement) {
59
		Element root = featureTreeElement.getChild("root");
60

    
61
		Element realRoot = factory.getTermNode(XMLHelper.getUuid(root));
62

    
63
		progressMonitor.subTask("Generating simplified Feature Tree.");
64
		simplifiedFeatureTree = featureTreeRecursive(realRoot);
65
		progressMonitor.worked(1);
66

    
67
		logger.info("Simplified FeeatureTree created");
68
	}
69

    
70
	private List<SimplifiedFeatureNode> featureTreeRecursive(Element featureNode){
71
		List<SimplifiedFeatureNode> result = new ArrayList<SimplifiedFeatureNode>();
72

    
73
		if(featureNode != null){
74
			Element children = featureNode.getChild("children");
75

    
76
			if (children != null){
77
				List<Element> childFeatureNodes = children.getChildren();
78

    
79
				for(Element childNode : childFeatureNodes){
80

    
81
					UUID uuid = XMLHelper.getUuid(childNode);
82
					Element featureNodeElement = factory.getTermNode(uuid);
83
					Element featureElement = factory.getFeatureForTermNode(uuid);
84

    
85

    
86
					try {
87
						Element featureTitleCache = (Element) XPath.selectSingleNode(featureElement, "//Feature/titleCache");
88

    
89
						logger.info("The featureNode uuid is " + uuid);
90
						logger.info("The feature element name is " + featureTitleCache.getValue());
91
						logger.info("The feature title cache text french is " + featureTitleCache.getText().toLowerCase(Locale.FRENCH));
92
						logger.info("The feature title cache value french is " + featureTitleCache.getValue().toLowerCase(Locale.FRENCH));
93

    
94
						featureTitleCache.setText(featureTitleCache.getText().toLowerCase(Locale.FRENCH));
95

    
96
					} catch (JDOMException e) {
97
						// TODO Auto-generated catch block
98
						e.printStackTrace();
99
					}
100

    
101
					////We set it to French here but this isn't the correct place the Feature/titleCache
102
					featureElement.setName(featureElement.getName().toLowerCase(Locale.FRENCH));
103
					SimplifiedFeatureNode simplifiedFeatureNode = new SimplifiedFeatureNode(featureElement, featureTreeRecursive(featureNodeElement));
104
					result.add(simplifiedFeatureNode);
105
				}
106
			}
107
		}
108

    
109
		return result;
110
	}
111

    
112
	private class SimplifiedFeatureNode{
113
		private Element featureElement;
114
		private List<SimplifiedFeatureNode> children;
115

    
116
		public SimplifiedFeatureNode(Element featureElement, List<SimplifiedFeatureNode> children){
117
			this.featureElement = featureElement;
118
			this.children = children;
119
		}
120

    
121
		/**
122
		 * @return the uuid
123
		 */
124
		public Element getFeatureElement() {
125
			return featureElement;
126
		}
127

    
128
		/**
129
		 * @return the children
130
		 */
131
		public List<SimplifiedFeatureNode> getChildren() {
132
			return children;
133
		}
134
	}
135

    
136
	/**
137
	 * Commences harvesting the given {@link List} of taxonNodeElements
138
	 *
139
	 * @param taxonNodeElements
140
	 * @return a {@link Document} containing the necessary XML needed by the {@link IPublishOutputModule IPublishOutputModules}
141
	 */
142
	public Document harvest(List<Element> taxonNodeElements){
143

    
144
		Element root = new Element(IXMLElements.ROOT);
145

    
146
		for(Element taxonNodeElement : taxonNodeElements){
147

    
148
			logger.warn("Adding taxonNodeElement " + taxonNodeElement.getChildText("uuid"));
149

    
150
			//temporarily filter c15e12c1-6118-4929-aed0-b0cc90f5ab22 as it's causing a lazyInitializationException
151
			if (!taxonNodeElement.getChildText("uuid").equals("c15e12c1-6118-4929-aed0-b0cc90f5ab22")) {
152
			taxonNodeElement.detach();
153

    
154
			populateTreeNodeContainer(taxonNodeElement);
155

    
156
			root.addContent(taxonNodeElement);
157
			}
158

    
159
		}
160

    
161

    
162
		Document result = new Document();
163

    
164
		result.addContent(root);
165

    
166
		cleanDateFields(result);
167

    
168

    
169
		return result;
170
	}
171

    
172
	/**
173
	 * FIXME
174
	 * This is a hack to circumvent problems with the serialized version of
175
	 * datePublished objects. Remove this once this was fixed in the library
176
	 * @param element the context
177
	 */
178
	@Deprecated
179
	private void cleanDateFields(Object context) {
180
		String path = "//datePublished/start";
181

    
182
		try {
183
			List<Element> nodes = XPath.selectNodes(context, path);
184

    
185
			for(Element node : nodes){
186

    
187
				String textWithRubbish = node.getText() ;
188

    
189
				if (textWithRubbish.length() > 5) {
190
				String cleanedText = textWithRubbish.substring(0, 4);
191
				node.setText(cleanedText);
192
				}
193
				/*else {
194

    
195
					Element parentOfParent = (Element) node.getParent().getParent().getParent();
196

    
197
					if (parentOfParent.getName().equals("inReference")) {
198
					List<Element> parentNodes = XPath.selectNodes(parentOfParent, "//nomenclaturalReference/titleCache");
199
					for(Element parentNode : parentNodes){
200
					logger.error("Problem with date for node  with titleCache: " + parentNode.getText());
201
					}
202
					}
203
				}*/
204

    
205
				/*Element parent = (Element) node.getParent().getParent();
206

    
207
				if(parent.getName().equals("citation")){
208
					Element parent2 = (Element) parent.getParent();
209
					parent2.setAttribute("sort", cleanedText);
210
				}*/
211
			}
212
		} catch (Exception e) {
213
			logger.error("Error trying to clean date published field", e);
214
		}
215
	}
216

    
217
	/**
218
	 * Get all additional content that is not included in taxon node initialization
219
	 *
220
	 * @param container
221
	 */
222
	private void populateTreeNodeContainer(Element taxonNodeElement){
223

    
224
		// get the taxon from the generic service to have the uuid for further processing
225
		Element taxonElement = factory.getTaxonForTaxonNode(taxonNodeElement);
226

    
227
		progressMonitor.subTask("Gathering data for taxon: " + XMLHelper.getTitleCache(taxonElement));
228

    
229
		// get initialized accepted taxon
230
		// TODO right now we are getting that from the portal service but should consider to use the generic service
231
		// as the portal service is more likely to change
232
		Element fullTaxonElement = factory.getAcceptedTaxonElement(taxonElement);
233

    
234
		//populateTypeDesignations(fullTaxonElement);
235

    
236
		// get descriptions
237
		if(configurator.isDoDescriptions()){
238
			populateDescriptions(fullTaxonElement);
239
		}
240

    
241
		// get polytomous key
242

    
243
		if(configurator.isDoPolytomousKey()){
244
			populatePolytomousKey(fullTaxonElement);
245
		}
246

    
247
		// get synonym
248
		if(configurator.isDoSynonymy()){
249
			populateSynonyms(fullTaxonElement);
250
		}
251

    
252
		// get media
253
		if(configurator.isDoImages()){
254
			populateImages(fullTaxonElement);
255
		}
256

    
257
		// add taxon element to the node element
258
		XMLHelper.addContent(fullTaxonElement, taxonNodeElement);
259

    
260
		// get taxonomically included taxa
261
		if(configurator.isDoPublishEntireBranches()){
262
			populateChildren(taxonNodeElement);
263
		}
264

    
265
		try {
266
			populateReferences(fullTaxonElement);
267
		} catch (JDOMException e) {
268
			// TODO Auto-generated catch block
269
			e.printStackTrace();
270
		}
271

    
272
		populateTypeDesignations(fullTaxonElement);
273

    
274
		progressMonitor.worked(1);
275

    
276
	}
277

    
278
	// the name isn't populated in the taxonNode http://dev.e-taxonomy.eu/cdmserver/flora_central_africa/taxonNode/de808dae-e50a-42f2-a4da-bd12f2c2faaf/taxon.json
279
	// but can get the name from http://dev.e-taxonomy.eu/cdmserver/flora_central_africa/portal/taxon/8f6d5498-1f4b-420f-a1ae-3f0ed9406bb1.json
280
	private void populateTypeDesignations(Element fullTaxonElement) {
281

    
282
		Element nameElement = fullTaxonElement.getChild("name");
283
		Element uuidElement = fullTaxonElement.getChild("uuid");
284

    
285
		List<Element> typeDesignations = factory.getTypeDesignations(nameElement);
286

    
287
		nameElement.removeChild("typeDesignations");
288

    
289
		for(Element typeDesignation: typeDesignations){
290
			XMLHelper.addContent(typeDesignation, "typeDesignations", nameElement);
291
		}
292
	}
293

    
294
	private void populateReferences(Element fullTaxonElement) throws JDOMException {
295

    
296
		//get the references from the taxonElement
297
		//String referencePattern = "//name/nomenclaturalReference";
298
		String referencePattern = "/Taxon/name/nomenclaturalSource/citation";
299

    
300
		//but there could be many references
301
		Element referenceElement = (Element) XPath.selectSingleNode(fullTaxonElement, referencePattern); //Mon 1st july do we get the /Taxon/name/nomenclaturalSource/citation from the taxon node - is this working
302
		//List<Element> descriptionElementElements = XPath.selectNodes(context, featurePattern + "/..");
303

    
304
		List<Element> elementList = null;
305

    
306
		if(referenceElement != null){  //the referencePattern was found in the taxonElement
307

    
308
			List<Element> refs = factory.getReferences(referenceElement);//getReferences
309

    
310
			fullTaxonElement.removeChild("nomenclaturalSource");//remove the references  ;TODO after #6851 do we need to handle nomenclaturalSource.citation somehow?
311

    
312
			for(Element ref: refs){
313
				XMLHelper.addContent(ref, "nomenclaturalSource", fullTaxonElement);   //TODO after #6851 do we need to handle nomenclaturalSource.citation somehow?
314
			}
315
		}
316
	}
317

    
318
	/**
319
	 * Populates all child nodes of the given taxonNodeElement
320
	 *
321
	 * @param container
322
	 */
323
	private void populateChildren(Element taxonNodeElement){
324

    
325
		logger.info("populating branch");
326

    
327
		List<Element> childNodeElements = factory.getChildNodes(taxonNodeElement);
328

    
329
		for(Element childNodeElement : childNodeElements){
330

    
331
			populateTreeNodeContainer(childNodeElement);
332
			XMLHelper.addContent(childNodeElement, "childNodes", taxonNodeElement);
333
		}
334
	}
335

    
336
	private void populatePolytomousKey(Element taxonElement){
337

    
338
		logger.info("populating Polytomous key");
339
		logger.info("populating Polytomous key taxonElement " + XMLHelper.getUuid(taxonElement) + " name " + XMLHelper.getTitleCache(taxonElement));
340

    
341
		//List<Element> polytomousKey = factory.getPolytomousKey(taxonElement);
342
		Element polytomousKey = factory.getPolytomousKey(taxonElement);
343
		XMLHelper.addContent(polytomousKey, "key", taxonElement);
344

    
345
		/*for(Element keyRow : polytomousKey){
346
			XMLHelper.addContent(keyRow, "key", taxonElement);
347
		}*/
348

    
349
	}
350

    
351
	/**
352
	 * Retrieves descriptions for the given taxonElement and adds them to a SimplifiedFeatureNode
353
	 *
354
	 * @param taxonElement
355
	 */
356
	private void populateDescriptions(Element taxonElement){
357
		taxonElement.removeChild("descriptions");
358

    
359
		Element rawDescriptions = factory.getDescriptions(taxonElement);
360

    
361
		Element featureTitleCache;
362
		try {
363
			//featureTitleCache = (Element) XPath.selectSingleNode(rawDescriptions, "//feature/representation_L10n");
364
			List descs = XPath.selectNodes(rawDescriptions, "//feature/representation_L10n");
365
			for(Object des : descs){
366
				logger.info("The descriptions //feature/representation_L10n is " + ((Element) des).getValue());
367
			}
368

    
369
		} catch (JDOMException e1) {
370
			// TODO Auto-generated catch block
371
			e1.printStackTrace();
372
		}
373

    
374

    
375
		//logger.setLevel(Level.DEBUG);
376

    
377
		logger.debug("The taxonElement is " + XMLHelper.getUuid(taxonElement) + " name " + XMLHelper.getTitleCache(taxonElement));
378

    
379
		Element descriptionsElement = new Element("descriptions");
380
		Element featuresElement = new Element("features");
381

    
382
		for(SimplifiedFeatureNode simplifiedFeatureNode : simplifiedFeatureTree){
383

    
384
			try {
385

    
386
				processFeatureNode(simplifiedFeatureNode, rawDescriptions, featuresElement);
387

    
388
				//UUID featureUuid = XMLHelper.getUuid(simplifiedFeatureNode.getFeatureElement());
389
				//String featureTitleCache = XMLHelper.getTitleCache(simplifiedFeatureNode.getFeatureElement());
390
				//logger.debug(" The feature uuid is " + featureUuid + " and name is " + featureTitleCache);
391

    
392

    
393
			} catch (JDOMException e) {
394
				logger.error(e);
395
			}
396
		}
397
		XMLHelper.addContent(featuresElement, descriptionsElement);
398
		XMLHelper.addContent(descriptionsElement, taxonElement);
399
	}
400

    
401
	private void processFeatureNode(SimplifiedFeatureNode featureNode, Object context, Element parentFeatureElement)  throws JDOMException{
402

    
403
		// gets the feature elements with the current feature uuid
404
		UUID featureUuid = XMLHelper.getUuid(featureNode.getFeatureElement());
405

    
406
		String featurePatternold = "//feature[contains(uuid,'" + featureUuid + "')]";
407
		//String featurePattern = "/ArrayList[1]/e[1]/elements[1]/e[1]/feature/uuid[.='" + featureUuid + "']";
408
		//Xpath is now more specific so that only the feature associated with a particular Taxon and not the
409
		//Taxon's parent or children are selected.
410
		//Alternative would be to ensure the context object only contains descriptions for the Taxon element of interest
411
		//Need to look at the taxonPortalController.doGetDescriptions to change this
412
		String featurePattern = "/ArrayList[1]/e/elements/e/feature[contains(uuid,'" + featureUuid + "')]";
413

    
414
		Element feature = (Element) XPath.selectSingleNode(context, featurePattern);
415

    
416
		if(feature != null){  //the featurePattern was found in the raw descriptions data
417

    
418
			List<Element> descriptionElementElements = XPath.selectNodes(context, featurePattern + "/..");
419

    
420
			logger.debug("No of desc elements " +  descriptionElementElements.size() + " featureUUID " + featureUuid + " feature type is " + XMLHelper.getTitleCache(featureNode.getFeatureElement()));
421
			// add matching description elements as children to this feature element
422
			for(Element descriptionElementElement : descriptionElementElements){
423

    
424
				descriptionElementElement.removeChild("feature");
425
				descriptionElementElement.setName("descriptionelement");
426
				XMLHelper.addContent(descriptionElementElement, "descriptionelements", feature);
427

    
428
			}
429
			XMLHelper.addContent(feature, parentFeatureElement);
430
		}else if(featureNode.getChildren().size() > 0){
431

    
432
			Element featureElement = featureNode.getFeatureElement();
433
			Element featureElementClone = (Element) featureElement.clone();
434
			feature = (Element) featureElementClone.detach();
435

    
436
			XMLHelper.addContent(feature, parentFeatureElement);
437
		}
438

    
439
		// recurse into children
440
		for(SimplifiedFeatureNode childFeatureNode : featureNode.getChildren()){
441

    
442
			logger.debug("No of featureNode children " + featureNode.getChildren().size());//always 10
443

    
444
			UUID childFeatureUuid = XMLHelper.getUuid(childFeatureNode.getFeatureElement());
445
			String childFeatureTitleCache = XMLHelper.getTitleCache(childFeatureNode.getFeatureElement());
446
			logger.debug(" The feature is " + childFeatureUuid + " name " + childFeatureTitleCache);
447

    
448
			//9 features in each simplifiedFeatureNode but some of the feature elements are null for a particular featureTitleCache,
449
			//e.g. Ecology, Description - Description has child features
450

    
451
			//creates the second level features i.e. descriptions/features/feature/feature for the description
452
			processFeatureNode(childFeatureNode, context, feature);
453
		}
454
	}
455

    
456

    
457
	/*private Element processDescriptionsRecursive(Object context, SimplifiedFeatureNode simplifiedFeatureNode) throws JDOMException{
458
		// gets the feature elements with the current uuid
459
		String featurePattern = "//feature[contains(uuid,'" + simplifiedFeatureNode.getUuid() + "')]";
460

    
461
		Element feature = (Element) XPath.selectSingleNode(context, featurePattern);
462

    
463
		if(feature != null){
464
			// recurse into children
465
			for(SimplifiedFeatureNode childFeatureNode : simplifiedFeatureNode.getChildren()){
466
				Element childFeatureWithElements = processDescriptionsRecursive(context, childFeatureNode);
467
				XMLHelper.addContent(childFeatureWithElements, "features", feature);
468
			}
469

    
470
			// get the parents of all feature elements with the current uuid
471
			List<Element> descriptionElementElements = XPath.selectNodes(context, featurePattern + "/..");
472

    
473
			// add matching description elements as children to this feature element
474
			for(Element descriptionElementElement : descriptionElementElements){
475
				descriptionElementElement.removeChild("feature");
476
				descriptionElementElement.setName("descriptionelement");
477
				XMLHelper.addContent(descriptionElementElement, "descriptionelements", feature);
478
			}
479
		}
480

    
481
		return feature;
482
	}*/
483

    
484
	/**
485
	 * Retrieves the synonymy for the given taxonElement
486
	 *
487
	 * @param taxonElement
488
	 */
489
	private void populateSynonyms(Element taxonElement){
490
		List<Element> synonymy = factory.getSynonymy(taxonElement);
491

    
492
		for(Element synonymyNode : synonymy){
493

    
494
			List<Element> children = synonymyNode.getChildren("e");
495

    
496
			for(Element child : children){
497

    
498
				List<Element> children2 = child.getChildren("e");
499

    
500
				for(Element child2 : children2){
501

    
502
					if (child2.getChild("name") != null) {
503
						populateTypeDesignations(child2);// pass in the name of the synonym from synonymy/e/e/name
504
						//populateImages(child2);
505
						}
506

    
507
				}
508
			}
509

    
510
			XMLHelper.addContent(synonymyNode, "synonymy", taxonElement);
511
		}
512
	}
513

    
514

    
515

    
516
	/**
517
	 *
518
	 * @param taxonElement
519
	 */
520
	private void populateImages(Element taxonElement){
521

    
522
		factory.getMedia(taxonElement);
523
		logger.warn("Populating images");
524
		//Element nameElement = fullTaxonElement.getChild("name");
525
		//Element uuidElement = fullTaxonElement.getChild("uuid");
526

    
527
		List<Element> mediaElements = factory.getMedia(taxonElement);
528

    
529
		//nameElement.removeChild("typeDesignations");
530

    
531
		for(Element media: mediaElements){
532
			XMLHelper.addContent(media, "media", taxonElement);
533
		}
534
	}
535
}
(8-8/10)