Subversion Repositories SmartDukaan

Rev

Rev 2367 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2171 rajveer 1
/**
2
 * 
3
 */
4
package in.shop2020.util;
5
 
6
import in.shop2020.metamodel.core.Bullet;
7
import in.shop2020.metamodel.core.Entity;
8
import in.shop2020.metamodel.core.Feature;
9
import in.shop2020.metamodel.core.PrimitiveDataObject;
10
import in.shop2020.metamodel.core.Slide;
11
import in.shop2020.metamodel.definitions.BulletDefinition;
12
import in.shop2020.metamodel.definitions.Catalog;
13
import in.shop2020.metamodel.definitions.Category;
14
import in.shop2020.metamodel.definitions.DatatypeDefinition;
15
import in.shop2020.metamodel.definitions.DefinitionsContainer;
16
import in.shop2020.metamodel.definitions.FacetDefinition;
17
import in.shop2020.metamodel.definitions.FacetSlideDefinition;
18
import in.shop2020.metamodel.definitions.FeatureDefinition;
19
import in.shop2020.metamodel.util.CreationUtils;
20
import in.shop2020.metamodel.util.ExpandedBullet;
21
import in.shop2020.metamodel.util.ExpandedBulletDefinition;
22
import in.shop2020.metamodel.util.ExpandedEntity;
23
import in.shop2020.metamodel.util.ExpandedFacetDefinition;
24
import in.shop2020.metamodel.util.ExpandedFacetSlideDefinition;
25
import in.shop2020.metamodel.util.ExpandedFeature;
26
import in.shop2020.metamodel.util.ExpandedFeatureDefinition;
27
import in.shop2020.metamodel.util.ExpandedSlide;
28
import in.shop2020.model.v1.catalog.Item;
29
 
30
import java.io.File;
31
import java.io.FileOutputStream;
32
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.HashMap;
35
import java.util.LinkedHashMap;
36
import java.util.List;
37
import java.util.Map;
38
 
39
import javax.xml.transform.TransformerFactory;
40
import javax.xml.transform.Transformer;
41
import javax.xml.transform.stream.StreamResult;
42
import javax.xml.transform.stream.StreamSource;
43
 
44
import org.apache.commons.lang.StringEscapeUtils;
45
import org.apache.commons.lang.StringUtils;
46
 
47
 
48
/**
49
 * Command line utility to convert IR Definitions into IR Data and IR Meta-data
50
 * 
51
 * @author rajveer
52
 *
53
 */
54
public class NewIR {
55
 
56
	/**
57
	 * Level - 4, 8, 12, 16
58
	 */
59
	private String[] xmlIndentation = {"", "    ", "        ", "            ","                "};
60
 
61
	private String[] xmlTabIndentation = {"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t", "\t\t\t\t\t\t"};
62
 
63
	private Map<Long, List<String>> facetIDFacetValues = new HashMap<Long, List<String>>();
64
 
65
	Map<Long, List<Item>> entityIdItemMap;
66
 
67
	/**
68
	 * @param args
69
	 * @throws Exception 
70
	 */
71
	public static void main(String[] args) throws Exception {
72
		/*
73
		NewIR ir = new NewIR();
74
		ir.exportIRData();
75
		ir.transformIrDataXMLtoSolrXML();
76
		ir.exportIRMetaData();
77
		ir.transformIrMetaDataXMLSolrSchemaXML();
78
		*/
79
	}
80
 
81
	/**
82
	 * 
83
	 * @param entityIdItemMap
84
	 */
85
	public NewIR(Map<Long, List<Item>> entityIdItemMap){
86
	    this.entityIdItemMap = entityIdItemMap;
87
	}
88
 
89
 
90
	/**
91
	 * 
92
	 * @param inXMLFilename
93
	 * @param xslFilename
94
	 * @param outXMLFilename
95
	 * @throws Exception 
96
	 */
97
 
98
	public void xsltTransformation(String inXMLFilename, String xslFilename, String outXMLFilename) throws Exception{
99
		// Use the static TransformerFactory.newInstance() method to instantiate 
100
		  // a TransformerFactory. The javax.xml.transform.TransformerFactory 
101
		  // system property setting determines the actual class to instantiate --
102
		  // org.apache.xalan.transformer.TransformerImpl.
103
		TransformerFactory tFactory = TransformerFactory.newInstance();
104
 
105
			// Use the TransformerFactory to instantiate a Transformer that will work with  
106
			// the stylesheet you specify. This method call also processes the stylesheet
107
		  // into a compiled Templates object.
108
		Transformer transformer = tFactory.newTransformer(new StreamSource(xslFilename));
109
 
110
			// Use the Transformer to apply the associated Templates object to an XML document
111
			// (foo.xml) and write the output to a file (foo.out).
112
		transformer.transform(new StreamSource(inXMLFilename), new StreamResult(new FileOutputStream(outXMLFilename)));
113
 
114
	}
115
 
116
	/**
117
	 * 
118
	 * @throws Exception
119
	 */
120
	public void transformIrDataXMLtoSolrXML() throws Exception {
121
		String irDataFilename = Utils.EXPORT_IR_PATH + "irdata.xml";
122
		String irSolrDataFilename = Utils.EXPORT_SOLR_PATH + "irdata_solr.xml";
123
		String irXslFilename = "src/xsl/irdata_solrdata.xsl";
124
		System.out.println(irSolrDataFilename);
125
		File solrFile = new File(irSolrDataFilename);
126
		if(!solrFile.exists()){
127
			solrFile.createNewFile();
128
		}
129
		xsltTransformation(irDataFilename, irXslFilename, irSolrDataFilename);
130
	}
131
 
132
 
133
	/**
134
	 * 
135
	 * @throws Exception
136
	 */
137
	public void transformIrMetaDataXMLSolrSchemaXML() throws Exception {
138
		String irDataFilename = Utils.EXPORT_IR_PATH + "irmetadata.xml";
139
		String irSolrDataFilename = Utils.EXPORT_SOLR_PATH + "irmetadata_solrschema.xml";
140
		String irXslFilename = "src/xsl/irmetadata_solrschema.xsl";
141
		System.out.println(irSolrDataFilename);
142
		File solrFile = new File(irSolrDataFilename);
143
		if(!solrFile.exists()){
144
			solrFile.createNewFile();
145
		}
146
		xsltTransformation(irDataFilename, irXslFilename, irSolrDataFilename);
147
	}
148
 
149
 
150
 
151
	/**
152
	 * 
153
	 * @throws Exception
154
	 */
155
	public void exportIRMetaData() throws Exception {
156
		DefinitionsContainer defs = 
157
			Catalog.getInstance().getDefinitionsContainer();
158
 
159
		// <IRMetaData>
160
		List<String> xmlSnippets = new ArrayList<String>();
161
		xmlSnippets.add("<IRMetaData>");
162
		xmlSnippets.add("\t<Facets>");
163
 
164
		IRMetaDataJythonWrapper jy = new IRMetaDataJythonWrapper();
165
 
166
		// Iterate over all facet definitions
167
		Map<Long, FacetDefinition> facetDefs = defs.getFacetDefinitions();
168
		for(FacetDefinition facetDef : facetDefs.values()) {
169
 
170
			jy.reset();
171
			jy.initialize();
172
 
173
			ExpandedFacetDefinition expFacetDef = 
174
				new ExpandedFacetDefinition(facetDef);
175
 
176
			jy.setExpandedFacetDefinition(expFacetDef);
177
 
178
			jy.setPossibleValues(facetIDFacetValues.get(facetDef.getID()));
179
 
180
			jy.executeRule();
181
 
182
			String facetXMLSnip = jy.getXMLSnippet();
183
			Utils.info("facetXMLSnip=" + facetXMLSnip);
184
 
185
			xmlSnippets.add(facetXMLSnip);
186
 
187
		}
188
		xmlSnippets.add("\t</Facets>");
189
 
190
 
191
 
192
		xmlSnippets.add("\n\t<Properties>");
193
 
194
		// Iterate over all feature definitions
195
		Map<Long, FeatureDefinition> featureDefs = defs.getFeatureDefinitions();
196
		for(FeatureDefinition featureDef : featureDefs.values()) {
197
			String propertyXMLSnip = this.getPropertyXMLSnippet(featureDef);
198
			Utils.info("propertyXMLSnip=" + propertyXMLSnip);
199
 
200
			xmlSnippets.add(propertyXMLSnip);
201
		}
202
 
203
		xmlSnippets.add("\t</Properties>");
204
 
205
		xmlSnippets.add("\n\t<Categories>");
206
 
207
		// Iterate over all categories
208
		/*
209
		Category rootCategory = defs.getCategory(Catalog.getInstance().getRootCategory().getID());
210
		List<Category> children = rootCategory.getChildrenCategory();
211
		for (Category child : children) {
212
 
213
			String categoryXMLSnip = this.getCategoryXMLSnippet(child, 2);
214
			Utils.info("categoryXMLSnip=" + categoryXMLSnip);
215
 
216
			xmlSnippets.add(categoryXMLSnip);
217
		}
218
		*/
219
 
220
		Category rootCategory = defs.getCategory(Catalog.getInstance().getRootCategory().getID());
221
		String categoryXMLSnip = this.getCategoryXMLSnippet(rootCategory, 2);
222
		Utils.info("categoryXMLSnip=" + categoryXMLSnip);
223
 
224
		xmlSnippets.add(categoryXMLSnip);
225
 
226
 
227
		xmlSnippets.add("\t</Categories>");
228
 
229
		// </IRMetaData>
230
		xmlSnippets.add("</IRMetaData>");
231
 
232
		String irMetaDataXML = StringUtils.join(xmlSnippets, "\n");
233
		Utils.info(irMetaDataXML);
234
 
235
		// Write it to file
236
		String irMetaDataFilename = Utils.EXPORT_IR_PATH + "irmetadata.xml";
237
		DBUtils.store(irMetaDataXML, irMetaDataFilename);
238
	}
239
 
240
	/**
241
	 * 
242
	 * @param category
243
	 * @return
244
	 * @throws Exception 
245
	 */
246
	private String getCategoryXMLSnippet(Category category, int indent) 
247
		throws Exception {
248
 
249
		DefinitionsContainer defs = 
250
			Catalog.getInstance().getDefinitionsContainer();
251
 
252
		String xmlSnip = this.xmlTabIndentation[indent] + "<Category";
253
 
254
		xmlSnip += " ID=\"" + category.getID() + "\"";
255
		xmlSnip += " label=\"" + category.getLabel() + "\"";
256
		xmlSnip += ">\n";
257
 
258
		List<Category> children = category.getChildrenCategory();
259
 
260
		if(children != null) {
261
			for(Category child : children) {
262
				xmlSnip += this.getCategoryXMLSnippet(child, indent+1);
263
			}
264
		}
265
		else {
266
			// Only leaf category will have entities
267
			// Facet IDs
268
			xmlSnip += this.xmlTabIndentation[indent+1] + "<Facets>\n";
269
 
270
			List<Long> facetDefIDs = 
271
				defs.getFacetDefinitionIDs(category.getID());
272
			//Utils.info("facetDefIDs=" + facetDefIDs);
273
 
274
 
275
 
276
			if( facetDefIDs != null && !facetDefIDs.isEmpty() ){
277
					for(Long facetDefID : facetDefIDs) {
278
					xmlSnip += this.xmlTabIndentation[indent+2] + 
279
						"<FacetID>" + facetDefID + "</FacetID>\n";
280
				}
281
			}
282
 
283
 
284
			xmlSnip += this.xmlTabIndentation[indent+1] + "</Facets>\n\n";
285
 
286
			// Feature IDs
287
			xmlSnip += this.xmlTabIndentation[indent+1] + "<Properties>\n";
288
 
289
			List<Long> featureDefIDs = 
290
				defs.getFeatureDefinitionIDs(category.getID());
291
			//Utils.info("featureDefIDs=" + featureDefIDs);
292
 
293
			for(Long featureDefID : featureDefIDs) {
294
				xmlSnip += this.xmlTabIndentation[indent+2] + 
295
					"<FeatureID>" + featureDefID + "</FeatureID>\n";
296
			}
297
 
298
			xmlSnip += this.xmlTabIndentation[indent+1] + "</Properties>\n";
299
		}
300
 
301
		xmlSnip += this.xmlTabIndentation[indent] + "</Category>\n";
302
 
303
		return xmlSnip;
304
	}
305
 
306
	/**
307
	 * 
308
	 * @param featureDef
309
	 * @return
310
	 * @throws Exception 
311
	 */
312
	private String getPropertyXMLSnippet(FeatureDefinition featureDef) 
313
		throws Exception {
314
		String xmlSnip = "\t\t<Property";
315
 
316
		xmlSnip += " ID=\"" + featureDef.getID() + "\"";
317
		xmlSnip += " label=\"" + featureDef.getLabel() + "\"";
318
 
319
		ExpandedFeatureDefinition expFeatureDef = 
320
			new ExpandedFeatureDefinition(featureDef);
321
 
322
		ExpandedBulletDefinition expBulletDef = 
323
			expFeatureDef.getExpandedBulletDefinition();
324
 
325
		String datatype = "string";
326
		if(expBulletDef.isComposite() || expBulletDef.isEnumerated()) {
327
			datatype = "string";
328
		}
329
		else {
330
			DatatypeDefinition datatypeDef = 
331
				expBulletDef.getDatatypeDefinition();
332
 
333
			datatype = datatypeDef.getName();
334
 
335
			// REVISIT
336
			if(datatype.equals("hours_mins") || datatype.equals("days_hours") ||
337
					datatype.equals("hours_mins") || 
338
					datatype.equals("days_hours")) {
339
				datatype = "string";
340
			}
341
		}
342
		xmlSnip += " datatype=\"" + datatype + "\"";
343
 
344
		String multivalue = "false";
345
		if (expBulletDef.isMultivalue()) {
346
			multivalue = "true";
347
		}
348
		xmlSnip += " isMultivalue=\"" + multivalue + "\"";
349
 
350
		xmlSnip += "/>";
351
		return xmlSnip;
352
	}
353
 
354
 
355
 
356
	private String processFacet(FacetDefinition facet, ExpandedSlide expSlide, ExpandedFacetSlideDefinition expFacetSlideDef, Long facetDefID) throws Exception {
357
 
358
		IRDataJythonWrapper jw = new IRDataJythonWrapper();
359
 
360
		jw.setExpandedSlide(expSlide);
361
		jw.setExpandedFacetSlideDefinition(expFacetSlideDef);
362
 
363
		// Execute Python script
364
		jw.executeRule();
365
 
366
		//FIXME
367
		// Normalize
368
//		if(defs.needsNormalization(feature.getFeatureDefinitionID())) {
369
//			Utils.info("needsNormalization feature=" + feature.getFeatureDefinitionID());
370
//			
371
//			feature = this.normalize(feature);
372
//		}
373
 
374
 
375
 
376
		List<Object> values = (List<Object>)jw.getValues();
377
		Utils.info("values=" + values);
378
 
379
		// Append to facet values
380
 
381
		Utils.info("facetDefID=" + facetDefID);
382
 
383
		List<String> facetValues = this.facetIDFacetValues.get(
384
				new Long(facetDefID));
385
 
386
		if(facetValues == null) {
387
			facetValues = new ArrayList<String>();
388
			this.facetIDFacetValues.put(new Long(facetDefID), facetValues);
389
		}
390
 
391
		if(values != null) {
392
			for(Object value : values) {
393
				String strValue = value.toString();
394
 
395
				if(!facetValues.contains(strValue)) {
396
					facetValues.add(strValue);
397
				}
398
			}
399
		}
400
 
401
		ExpandedFacetDefinition expFacet = new ExpandedFacetDefinition(facet);
402
		// Parse returned Python list
403
		String facetXMLSnip = null;
404
		if(values != null) {
405
			facetXMLSnip = this.getFacetXMLSnippet(expFacet, values, 2);
406
		}
407
 
408
		Utils.info("0 facetXMLSnip=" + facetXMLSnip);
409
		return facetXMLSnip;
410
	}
411
 
412
 
413
 
414
	/**
415
	 * 
416
	 * @param expFacetDef
417
	 * @param values
418
	 * @param indent
419
	 * @return String XML Snippet
420
	 */
421
	private String getFacetXMLSnippet(ExpandedFacetDefinition expFacetDef,	List<Object> values, int indent) {
422
 
423
		// <Facet Label="Form Factor">
424
		List<String> xmlSnippet = new ArrayList<String>();
425
		String target = expFacetDef.getTarget();
426
 
427
		xmlSnippet.add(this.xmlIndentation[indent] + "<Facet ID=\"" + expFacetDef.getID() + "\" Label=\"" + target + "\">");
428
 
429
		//<Value>Candybar</Value>
430
		for(Object value : values) {
431
			xmlSnippet.add(this.xmlIndentation[indent + 1] + "<Value>" + value.toString() + "</Value>");
432
		}
433
 
434
		//</Facet>
435
		xmlSnippet.add(this.xmlIndentation[indent] + "</Facet>");
436
 
437
		return StringUtils.join(xmlSnippet, "\n");
438
	}
439
 
440
	/**
441
	 * @throws Exception 
442
	 * 
443
	 */
444
	public void exportIRData() throws Exception {
445
		DefinitionsContainer defs = Catalog.getInstance().getDefinitionsContainer();
446
		Map<Long, List<FacetDefinition>> slideFacets = defs.getSlideFacetDefinitions();
447
 
448
		// <IRData>
449
		List<String> irDataXMLSnippets = new ArrayList<String>();
450
		irDataXMLSnippets.add("<IRData>");
451
 
452
 
453
		for(long entityID: entityIdItemMap.keySet()){
454
		    Entity entity = CreationUtils.getEntity(entityID);
455
 
456
		    double minPrice = getMinPrice(entityIdItemMap.get(entityID));
457
 
458
			ExpandedEntity expEntity = new ExpandedEntity(entity);
459
			long categoryID = expEntity.getCategoryID();
460
			List<ExpandedSlide> expSlides = expEntity.getExpandedSlides();
461
 
462
			List<String> entityXMLSnippets = new ArrayList<String>();
463
			entityXMLSnippets.add(this.xmlIndentation[1] + "<Entity ID=\""+ entityID +"\">");
464
 
465
			String parentCategory = expEntity.getCategory().getLabel();
466
			entityXMLSnippets.add(this.xmlIndentation[2] + "<Category>" + StringEscapeUtils.escapeXml(parentCategory) + "</Category>");
467
 
468
 
469
			String title = StringEscapeUtils.escapeXml(expEntity.getBrand()) + " " + StringEscapeUtils.escapeXml(expEntity.getModelName()) + 
470
				((expEntity.getModelNumber() != null) ? (" " +	StringEscapeUtils.escapeXml(expEntity.getModelNumber())): "");
471
 
472
			entityXMLSnippets.add(this.xmlIndentation[2] +	"<Title>" + StringEscapeUtils.escapeXml(title) + "</Title>");
473
 
474
			//Boost titles for the mobile phones
475
			if(expEntity.getCategory().getParentCategory().getID() == 10001){
476
			    entityXMLSnippets.add(this.xmlIndentation[2] +   "<Boost>" + 5 + "</Boost>");
477
			}else{
478
			    entityXMLSnippets.add(this.xmlIndentation[2] +   "<Boost>" + 0 + "</Boost>");
479
			}
480
 
481
 
482
			String subCategory = defs.getCategory(categoryID).getLabel();
483
			String  mainCategory = defs.getCategory(categoryID).getParentCategory().getLabel();
484
 
485
			String brand = expEntity.getBrand();
486
 
487
 
488
 
489
			//Create zero slide
490
			Slide zeroSlide = createZeroSlide(brand, minPrice, mainCategory, subCategory);
491
			ExpandedSlide expandedZeroSlide = new ExpandedSlide(zeroSlide);
492
			expSlides.add(expandedZeroSlide);
493
 
494
			for(ExpandedSlide expSlide: expSlides){
495
				System.out.println(expSlide.getSlideDefinitionID());
496
				if(slideFacets.containsKey(expSlide.getSlideDefinitionID())){
497
					List<FacetDefinition> facets = slideFacets.get(expSlide.getSlideDefinitionID());
498
					for(FacetDefinition facet: facets){
499
						for(FacetSlideDefinition facetSlides: facet.getFacetSlideDefinitions()){
500
							if(facetSlides.getSlideDefinitionID() != expSlide.getSlideDefinitionID()){continue;}
501
							ExpandedFacetSlideDefinition expFacetSlideDef = new ExpandedFacetSlideDefinition(facetSlides) ;
502
							for(ExpandedFeature expFeature: expSlide.getExpandedFeatures()){
503
								if(defs.needsNormalization(expFeature.getFeatureDefinitionID())) {
504
									Utils.info("needsNormalization feature=" + expFeature.getFeatureDefinitionID());
505
									//expFeature = this.normalize(expFeature);
506
								}
507
							}
508
							entityXMLSnippets.add(processFacet(facet, expSlide, expFacetSlideDef, facet.getID()));
509
						}
510
					}
511
				}
512
			}
513
 
514
			// Collect PROPERTIES
515
			String propertiesXMLSnippetsStr = this.getPropertiesXMLSnippet(expEntity, new ArrayList<Long>(), 2);
516
			entityXMLSnippets.add(propertiesXMLSnippetsStr);
517
			entityXMLSnippets.add(this.xmlIndentation[1] + "</Entity>");
518
			System.out.println(entityXMLSnippets);
519
			irDataXMLSnippets.addAll(entityXMLSnippets);
520
 
521
		}
522
 
523
		irDataXMLSnippets.add("</IRData>");
524
 
525
		String irDataXML = StringUtils.join(irDataXMLSnippets, "\n");
526
		Utils.info(irDataXML);
527
 
528
		// Write it to file
529
		String irDataFilename = Utils.EXPORT_IR_PATH + "irdata.xml";
530
		DBUtils.store(irDataXML, irDataFilename);
531
	}
532
 
533
	private double getMinPrice(List<Item> items){
534
        double minPrice = Double.MAX_VALUE;
535
        for(Item item: items){
536
            if(minPrice > item.getSellingPrice()){
537
                minPrice = item.getSellingPrice();
538
            }
539
        }
540
        return minPrice;
541
    }
542
 
543
 
544
 
545
	private Slide createZeroSlide(String brand, double price, String mainCategory, String subCategory) {
546
		Slide zeroSlide = new Slide(130000);
547
		List<Feature> zeroSlideFeatures = new ArrayList<Feature>();
548
 
549
		Feature brandFeature = new Feature(120080);
550
		Bullet brandBullet = new Bullet(new PrimitiveDataObject(brand));
551
		List<Bullet> brandBullets = new ArrayList<Bullet>();
552
		brandBullets.add(brandBullet);
553
		brandFeature.setBullets(brandBullets);
554
		zeroSlideFeatures.add(brandFeature);
555
 
556
		Feature priceFeature = new Feature(120128);
557
		Bullet priceBullet = new Bullet(new PrimitiveDataObject((new Double(price)).toString()));
558
		List<Bullet> priceBullets = new ArrayList<Bullet>();
559
		priceBullets.add(priceBullet);
560
		priceFeature.setBullets(priceBullets);
561
		zeroSlideFeatures.add(priceFeature);
562
 
563
		Feature mainCategoryFeature = new Feature(120123);
564
		Bullet mainCategoryBullet = new Bullet(new PrimitiveDataObject(mainCategory));
565
		List<Bullet> mainCategoryBullets = new ArrayList<Bullet>();
566
		mainCategoryBullets.add(mainCategoryBullet);
567
		mainCategoryFeature.setBullets(mainCategoryBullets);
568
		zeroSlideFeatures.add(mainCategoryFeature);
569
 
570
		Feature subCategoryFeature = new Feature(120124);
571
		Bullet subCategoryBullet = new Bullet(new PrimitiveDataObject(subCategory));
572
		List<Bullet> subCategoryBullets = new ArrayList<Bullet>();
573
		subCategoryBullets.add(subCategoryBullet);
574
		subCategoryFeature.setBullets(subCategoryBullets);
575
		zeroSlideFeatures.add(subCategoryFeature);
576
 
577
		zeroSlide.setFeatures(zeroSlideFeatures);
578
		return zeroSlide;
579
	}
580
 
581
 
582
	/**
583
	 * 
584
	 * @param feature
585
	 * @return Feature
586
	 * @throws Exception 
587
	 */
588
	private ExpandedFeature normalize(ExpandedFeature expFeature) throws Exception {
589
		BulletDefinition bulletDef = 
590
			expFeature.getFeatureDefinition().getBulletDefinition();
591
 
592
		ExpandedBulletDefinition expBulletDef = new ExpandedBulletDefinition(
593
				bulletDef);
594
 
595
		if(expBulletDef.isPrimitive()) {
596
			PrimitiveNormalizationJythonWrapper jy = 
597
				new PrimitiveNormalizationJythonWrapper();
598
 
599
			jy.setExpandedFeature(expFeature);
600
 
601
			jy.excuteRule();
602
 
603
			String newValue = jy.getNewValue();
604
			long newUnitID = jy.getNewUnitID();
605
 
606
			List<Bullet> newBullets = new ArrayList<Bullet>();
607
			Bullet newBullet = new Bullet(new PrimitiveDataObject(newValue));
608
			newBullet.setUnitID(newUnitID);
609
 
610
			newBullets.add(newBullet);
611
 
612
			expFeature.setBullets(newBullets);
613
		}
614
		else {
615
			Utils.severe("Normalization not defined for non-primitives");
616
		}
617
 
618
		return expFeature;
619
	}
620
 
621
	/**
622
	 * 
623
	 * @param expEntity
624
	 * @param facetFeatureIDs
625
	 * @param indent
626
	 * @return
627
	 */
628
	private String getPropertiesXMLSnippet(ExpandedEntity expEntity, 
629
			List<Long> facetFeatureIDs, int indent) {
630
 
631
		List<String> xmlSnippet = new ArrayList<String>();
632
 
633
		// Collect all free-form content here
634
		List<String> ffc = new ArrayList<String>();
635
 
636
		// Features
637
		List<ExpandedSlide> expSlides = expEntity.getExpandedSlides();
638
 
639
		for(ExpandedSlide expSlide : expSlides) {
640
			if(expSlide.getSlideDefinitionID() == 13000){
641
				continue;
642
			}
643
			List<ExpandedFeature> expFeatures = expSlide.getExpandedFeatures();
644
 
645
			if(expSlide.getFreeformContent() != null) {
646
				ffc.add(expSlide.getFreeformContent().getFreeformText());
647
			}
648
 
649
			if(expFeatures == null) {
650
				continue;
651
			}
652
 
653
			for(ExpandedFeature expFeature : expFeatures) {
654
				Long featureDefID = 
655
					new Long(expFeature.getFeatureDefinitionID());
656
 
657
				// FFC at feature level
658
				if(expFeature.getFreeformContent() != null) {
659
					ffc.add(expFeature.getFreeformContent().getFreeformText());
660
				}
661
 
662
				// Exclude those who are already covered as facets
663
				if(facetFeatureIDs.contains(featureDefID)) {
664
					continue;
665
				}
666
 
667
				List<ExpandedBullet> expBullets = 
668
					expFeature.getExpandedBullets();
669
 
670
				if(expBullets == null) {
671
					continue;
672
				}
673
 
674
				//<Property Label="">
675
				xmlSnippet.add(this.xmlIndentation[indent] + 
676
						"<Property ID=\"" + expFeature.getFeatureDefinitionID() 
677
						+ "\" Label=\"" + StringEscapeUtils.escapeXml(
678
								expFeature.getFeatureDefinition().getLabel()) + 
679
						"\">");
680
 
681
				//<Value></Value>
682
				for(ExpandedBullet bullet : expBullets) {
683
 
684
					// FFC at bullet level
685
					if(bullet.getFreeformContent() != null) {
686
						ffc.add(bullet.getFreeformContent().getFreeformText());
687
					}
688
 
689
					xmlSnippet.add(this.xmlIndentation[indent + 1] + "<Value>" + 
690
							StringEscapeUtils.escapeXml(bullet.getValue()) + 
691
							"</Value>");
692
				}
693
 
694
				//</Property>
695
				xmlSnippet.add(this.xmlIndentation[indent] + "</Property>");
696
			}
697
		}
698
 
699
		// FFC as Label="Free-form Content"
700
		if(!ffc.isEmpty()) {
701
			xmlSnippet.add(this.xmlIndentation[indent] + 
702
					"<Property ID=\"000000\" Label=\"Free-form Content\">");
703
 
704
			for(String f : ffc) {
705
				if(f != null) {
706
					f = StringEscapeUtils.escapeXml(f);
707
 
708
					xmlSnippet.add(this.xmlIndentation[indent + 1] + "<Value>" + 
709
						f + "</Value>");
710
				}
711
			}
712
 
713
			xmlSnippet.add(this.xmlIndentation[indent] + "</Property>");
714
		}
715
 
716
		// Children slides
717
		// TODO
718
 
719
		return StringUtils.join(xmlSnippet, "\n");
720
	}
721
 
722
}