Subversion Repositories SmartDukaan

Rev

Rev 2170 | Rev 4802 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/**
 * 
 */
package in.shop2020.metamodel.definitions;

import in.shop2020.metamodel.jaxb.comparison.CMPBucketDefinitionType;
import in.shop2020.metamodel.jaxb.comparison.CMPDefinitionType;
import in.shop2020.metamodel.jaxb.comparison.CMPRuleDefinitionType;
import in.shop2020.metamodel.jaxb.comparison.CMPSlideRuleDefinitionType;
import in.shop2020.metamodel.jaxb.core.BulletDefinitionType;
import in.shop2020.metamodel.jaxb.core.CategorySlideDefinitionType;
import in.shop2020.metamodel.jaxb.core.CategorySlideSequenceType;
import in.shop2020.metamodel.jaxb.core.CategoryType;
import in.shop2020.metamodel.jaxb.core.CompositeDefinitionType;
import in.shop2020.metamodel.jaxb.core.CompositePartDefinitionType;
import in.shop2020.metamodel.jaxb.core.DatatypeDefinitionType;
import in.shop2020.metamodel.jaxb.core.DefinitionType;
import in.shop2020.metamodel.jaxb.core.EditorialImportanceType;
import in.shop2020.metamodel.jaxb.core.EnumDefinitionType;
import in.shop2020.metamodel.jaxb.core.EnumValueType;
import in.shop2020.metamodel.jaxb.core.FeatureDefinitionType;
import in.shop2020.metamodel.jaxb.core.HelpDocDefinitionType;
import in.shop2020.metamodel.jaxb.core.SlideDefinitionType;
import in.shop2020.metamodel.jaxb.core.SlideFeatureDefinitionType;
import in.shop2020.metamodel.jaxb.core.UnitType;
import in.shop2020.metamodel.jaxb.facets.CategoryFacetDefinitionType;
import in.shop2020.metamodel.jaxb.facets.FacetDefinitionType;
import in.shop2020.metamodel.jaxb.facets.FacetSlideDefinitionType;
import in.shop2020.metamodel.jaxb.facets.IRDefinitionType;
import in.shop2020.metamodel.jaxb.facets.RuleDefinitionType;
import in.shop2020.metamodel.util.ExpandedCMPSlideRuleDefinition;
import in.shop2020.metamodel.util.ExpandedCategory;
import in.shop2020.metamodel.util.ExpandedCategoryFacetDefinition;
import in.shop2020.metamodel.util.ExpandedSlideDefinition;
import in.shop2020.util.Utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;

/**
 * Single point of access to all definition objects
 * 
 * @author naveen
 *
 */
public class DefinitionsContainer implements Serializable {

        /** 
         * 
         */
        private static final long serialVersionUID = 1L;
        
        /**
         * Hashtable of Category ID to Category object
         */
        private Map<Long, Category> categories;
        
        /**
         * Hashtable of Slide ID to SlideDefinition object
         */
        private Map<Long, SlideDefinition> slideDefinitions;
        
        /**
         * Hashtable of Feature Definition ID to FeatureDefinition object
         */
        private Map<Long, FeatureDefinition> featureDefinitions;
        
        /**
         * Hashtable of Datatype Definition ID to DatatypeDefinition object
         */
        private Map<Long, DatatypeDefinition> datatypeDefinitions;
        
        /**
         * Hashtable of Enum value ID to EnumValue object
         */
        private Map<Long, EnumValue> enumValues;
        
        /**
         * Hashtable of Unit ID to Unit object
         */
        private Map<Long, Unit> units;
        
        /**
         * Hashtable of Facet Definition ID to FacetDefinition object
         */
        private Map<Long, FacetDefinition> facetDefinitions;
        

        /**
         * Hashtable of Slide Definition ID to FacetDefinition object
         */
        private Map<Long, List<FacetDefinition>> slideFacetDefinitions;

        /**
         * Hashtable of Category Facet Definition ID to CategoryFacetDefinition 
         * object
         */
        private Map<Long, CategoryFacetDefinition> categoryFacetDefinitions;
        
        /**
         * Hashtable of IR Data Rule ID to RuleDefinition object
         */
        private Map<Long, RuleDefinition> irDataRuleDefinitions;        
        
        /**
         * Hashtable of IR Meta Data Rule ID to RuleDefinition object
         */
        private Map<Long, RuleDefinition> irMetaDataRuleDefinitions;

        
        /**
         * Hashtable of Comparison Rule ID to CMPRuleDefinition object
         */
        private Map<Long, CMPRuleDefinition> cmpRuleDefinitions;        
        
        /**
         * Hashtable of SlideDefinition ID to CMPSlideRuleDefinition object
         */
        private Map<Long, CMPSlideRuleDefinition> cmpSlideRuleDefinitions;
        
        /**
         * Hashtable of Category ID to list of CMPBucketDefinition object
         */
        private Map<Long, List<CMPBucketDefinition>> cmpBucketDefinitions;

        /**
         * Hashtable of feature definition ID to normalization rule definition ID
         */
        private Map<Long, RuleDefinition> normalizationRuleDefinitions;
        
        /**
         * Hashtable of help doc definition ID to help doc definition object
         */
        private Map<Long, HelpDocDefinition> helpDocDefinitions;

        /**
         * Hashtable of feature definition ID to normalization rule definition ID
         */
        private Map<Long, List<Long>> categorySlideSequence;
        
        /**
         * Database path. Just in case we want to override
         */
        private String xmlDefinitionsPath =  Utils.CONTENT_DB_PATH + "definitions" + File.separator;
        
        /**
         * Empty constructor. Data structures are initialised as needed
         * @throws Exception 
         */
        public DefinitionsContainer(){
                try {
                        initialize();
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
        }
        
        /**
         * Empty constructor. Just dbPath is initialised
         * @throws Exception 
         */
        public DefinitionsContainer(String xmlDefinitionsPath) throws Exception {
                this.xmlDefinitionsPath = xmlDefinitionsPath;
                initialize();
        }

        
        private void initialize() throws Exception{
                initializeCoreDefinitionObjects();
                initializeFacetsDefinitionObjects();
                initializeComparisonDefinitionObjects();
        }
        
        private void initializeCoreDefinitionObjects() throws Exception{
                DefinitionType defType = null;
                String srcFile;
                Object oDefType = null;

                // categoriy slide sequence
                srcFile = xmlDefinitionsPath+ "categories.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "core");
                defType = (DefinitionType)oDefType;
                //FIXME
                categories = new HashMap<Long, Category>();
                Category root = this.convertCategories(defType, categories, srcFile);
                
                // category slide sequence
                srcFile = xmlDefinitionsPath+ "categoryslidesequence.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "core");
                defType = (DefinitionType)oDefType;
                this.categorySlideSequence = this.convertCategorySlideSequence(defType);
                
                // units
                srcFile = xmlDefinitionsPath+ "units.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "core");
                defType = (DefinitionType)oDefType;
                this.units = this.convertUnits(defType);

                //data type definitions
                srcFile = xmlDefinitionsPath+ "datatypedefinitions.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "core");
                defType = (DefinitionType)oDefType;
                this.datatypeDefinitions = this.convertDatatypeDefinition(defType);
                
                //enum values
                populateEnumValues();
                
                //feature definitions
                srcFile = xmlDefinitionsPath+ "featuredefinitions.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "core");
                defType = (DefinitionType)oDefType;
                this.featureDefinitions = this.convertFeatureDefinitions(defType);
                
                //slide definitions
                srcFile = xmlDefinitionsPath+ "slidedefinitions.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "core");
                defType = (DefinitionType)oDefType;
                this.slideDefinitions = this.convertSlideDefinitions(defType);
                
            //help doc definition
        srcFile = xmlDefinitionsPath+ "helpdocdefinitions.xml";
        oDefType = this.unmarshallSrcFile(srcFile, "core");
        defType = (DefinitionType)oDefType;
        this.helpDocDefinitions = this.convertHelpDocDefinitions(defType);

        }
        
        private void initializeFacetsDefinitionObjects() throws Exception{
                IRDefinitionType irDefType = null;
                String srcFile;
                Object oDefType = null;

                //all facet definitions
                srcFile = xmlDefinitionsPath+ "facetdefinitions.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "facets");
                irDefType = (IRDefinitionType)oDefType;
                this.facetDefinitions = this.convertFacetDefinitions(irDefType);
                
                //
                this.populateSlideFacetDefinitions();
                
                //category facet definitions
                srcFile = xmlDefinitionsPath+ "categoryfacetdefinitions.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "facets");
                irDefType = (IRDefinitionType)oDefType;
                this.categoryFacetDefinitions = this.convertCategoryFacetDefinitions(irDefType);
                
                
                //ir data rules
                srcFile = xmlDefinitionsPath+ "irdatarules.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "facets");
                irDefType = (IRDefinitionType)oDefType;
                irDataRuleDefinitions =  this.convertRuleDefinitions(irDefType);
                
                //ir meta data rules
                srcFile = xmlDefinitionsPath+ "irmetadatarules.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "facets");
                irDefType = (IRDefinitionType)oDefType;
                irMetaDataRuleDefinitions =  this.convertRuleDefinitions(irDefType);

                //normalization rules
                srcFile = xmlDefinitionsPath+ "normalizationrules.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "facets");
                irDefType = (IRDefinitionType)oDefType;
                normalizationRuleDefinitions = this.convertNormalizationRuleDefinitions(irDefType);
        }
        
        private void initializeComparisonDefinitionObjects() throws Exception{
                CMPDefinitionType cmpDefType = null;
                String srcFile;
                Object oDefType = null;

                //all facet definitions
                srcFile = xmlDefinitionsPath+ "comparisonrules.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "comparison");
                cmpDefType = (CMPDefinitionType)oDefType;
                this.cmpRuleDefinitions = this.convertComparisonRuleDefinitions(cmpDefType);

                
                //all f
                srcFile = xmlDefinitionsPath+ "comparisondefinitions.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "comparison");
                cmpDefType = (CMPDefinitionType)oDefType;
                this.cmpSlideRuleDefinitions = this.convertComparisonDefinitions(cmpDefType);
                
                //all facet definitions
                srcFile = xmlDefinitionsPath+ "comparisonbuckets.xml";
                oDefType = this.unmarshallSrcFile(srcFile, "comparison");
                cmpDefType = (CMPDefinitionType)oDefType;
                this.cmpBucketDefinitions = this.convertComparisonBuckets(cmpDefType);
                
        }

        
        /**
         * 
         * @param irDefType
         * @return
         */
        private Map<Long, RuleDefinition> convertNormalizationRuleDefinitions(
                        IRDefinitionType defType) {
                
                Map<Long, RuleDefinition> idRuleDef = 
                        new TreeMap<Long, RuleDefinition>();
                
                List<RuleDefinitionType> jaxbRuleDefs = defType.getRuleDefinition();
                
                for(RuleDefinitionType jaxbRuleDef : jaxbRuleDefs) {
                        long id = jaxbRuleDef.getID();
                        String script = jaxbRuleDef.getScript();
                        
                        RuleDefinition ruleDef = new RuleDefinition(id, script);
                        ruleDef.setDescription(jaxbRuleDef.getDescription());
                        
                        idRuleDef.put(new Long(id), ruleDef);
                }
                
                Utils.info("idRuleDef=" + idRuleDef);
                
                return idRuleDef;
        }

        
        
        /**
         * 
         * @param defType
         * @return Map<Long, CMPRuleDefinition>
         */
        private Map<Long, CMPRuleDefinition> convertComparisonRuleDefinitions(
                        CMPDefinitionType defType) {
                Map<Long, CMPRuleDefinition> idRuleDef = 
                        new TreeMap<Long, CMPRuleDefinition>();
                
                List<CMPRuleDefinitionType> jaxbRuleDefs = 
                        defType.getCMPRuleDefinition();
                
                for(CMPRuleDefinitionType jaxbRuleDef : jaxbRuleDefs) {
                        long id = jaxbRuleDef.getID();
                        String script = jaxbRuleDef.getScript();
                        
                        CMPRuleDefinition ruleDef = new CMPRuleDefinition(id, script);
                        ruleDef.setDescription(jaxbRuleDef.getDescription());
                        
                        idRuleDef.put(new Long(id), ruleDef);
                }
                
                Utils.info("idRuleDef=" + idRuleDef);
                return idRuleDef;
        }
        
        /**
         * 
         * @param defType
         * @return Map<Long, CMPSlideRuleDefinition> 
         */
        private Map<Long, CMPSlideRuleDefinition> convertComparisonDefinitions(
                        CMPDefinitionType defType) {
                
                Map<Long, CMPSlideRuleDefinition> slideRuleDefs = 
                        new TreeMap<Long, CMPSlideRuleDefinition>();
                
                List<CMPSlideRuleDefinitionType> jaxbDefs = 
                        defType.getCMPSlideRuleDefinition();
                
                for(CMPSlideRuleDefinitionType jaxbDef : jaxbDefs) {
                        long ruleDefID = jaxbDef.getRuleDefinitionID();
                        long slideDefID = jaxbDef.getSlideDefinitionID();
                        
                        CMPSlideRuleDefinition slideRuleDef = 
                                new CMPSlideRuleDefinition(slideDefID, ruleDefID);
                        
                        slideRuleDef.setDescription(jaxbDef.getDescription());
                        
                        slideRuleDefs.put(new Long(slideDefID), slideRuleDef);
                }
                
                Utils.info("slideRuleDefs=" + slideRuleDefs);
                return slideRuleDefs;
        }
        
        /**
         * 
         * @param defType
         * @return
         */
        private Map<Long, List<CMPBucketDefinition>> convertComparisonBuckets(
                        CMPDefinitionType defType) {
                
                Map<Long, List<CMPBucketDefinition>> cmpBuckets = 
                        new HashMap<Long, List<CMPBucketDefinition>>();
                
                List<CMPBucketDefinitionType> jaxbBuckets = 
                        defType.getCMPBucketDefinition();
                
                for(CMPBucketDefinitionType jaxbBucket : jaxbBuckets) {
                        String name = jaxbBucket.getName();
                        long categoryID = jaxbBucket.getCategoryID();
                        
                        CMPBucketDefinition bucketDef = 
                                new CMPBucketDefinition(name, categoryID);
                        
                        bucketDef.setDescription(jaxbBucket.getDescription());
                        bucketDef.setDefaultWeight(
                                        jaxbBucket.getDefaultWeight().intValue());
                        bucketDef.setSlideDefinitionIDs(jaxbBucket.getSlideDefinitionID());
                        
                        List<CMPBucketDefinition> categoryBuckets = 
                                cmpBuckets.get(new Long(categoryID));
                        
                        if(categoryBuckets == null) {
                                categoryBuckets = new ArrayList<CMPBucketDefinition>();
                                cmpBuckets.put(new Long(categoryID), categoryBuckets);
                        }
                        
                        categoryBuckets.add(bucketDef);
                }
                Utils.info("cmpBuckets=" + cmpBuckets);
                
                return cmpBuckets;
        }

        
        /**
         * 
         * @param defType
         * @return
         */
        private Map<Long, RuleDefinition> convertRuleDefinitions(
                        IRDefinitionType defType) {
                Map<Long, RuleDefinition> idRuleDef = 
                        new TreeMap<Long, RuleDefinition>();
                
                List<RuleDefinitionType> jaxbRuleDefs = defType.getRuleDefinition();
                
                for(RuleDefinitionType jaxbRuleDef : jaxbRuleDefs) {
                        long id = jaxbRuleDef.getID();
                        String script = jaxbRuleDef.getScript();
                        
                        RuleDefinition ruleDef = new RuleDefinition(id, script);
                        ruleDef.setDescription(jaxbRuleDef.getDescription());
                        
                        idRuleDef.put(new Long(id), ruleDef);
                }
                
                Utils.info("idRuleDef=" + idRuleDef);
                return idRuleDef;
        }

        
        /**
         * 
         * @param defType
         * @return
         */
        private Map<Long, FacetDefinition> convertFacetDefinitions(
                        IRDefinitionType defType) {
                List<FacetDefinitionType> jaxbFacetDefs = defType.getFacetDefinition();
                
                Map<Long, FacetDefinition> idFacetDefs = 
                        new TreeMap<Long, FacetDefinition>();
                
                for(FacetDefinitionType jaxbFacetDef : jaxbFacetDefs) {
                        long id = jaxbFacetDef.getID();
                        String target = jaxbFacetDef.getTarget();

                        FacetDefinition facetDef = new FacetDefinition(id, target);
                        
                        List<FacetSlideDefinition> facetSlideDefinitions = convertFacetSlideDefinitions(jaxbFacetDef);
                        
                        facetDef.setFacetSlideDefinitions(facetSlideDefinitions);
                        
                        facetDef.setDescription(jaxbFacetDef.getDescription());
                        
                        idFacetDefs.put(new Long(id), facetDef);
                        
                }
                Utils.info("idFacetDefs=" + idFacetDefs);
                return idFacetDefs;
        }
        
        private void populateSlideFacetDefinitions() {
                this.slideFacetDefinitions = new HashMap<Long, List<FacetDefinition>>();
                for(FacetDefinition facetDef: facetDefinitions.values())
                        for(FacetSlideDefinition facetSlideDef: facetDef.getFacetSlideDefinitions()){
                                List<FacetDefinition> facetDefs = this.slideFacetDefinitions.get(facetSlideDef.getSlideDefinitionID());
                                if(facetDefs==null){
                                        facetDefs = new ArrayList<FacetDefinition>();
                                }
                                facetDefs.add(facetDef);
                                this.slideFacetDefinitions.put(facetSlideDef.getSlideDefinitionID(), facetDefs);
                        }
        }
        
        private List<FacetSlideDefinition> convertFacetSlideDefinitions(
                        FacetDefinitionType jaxbFacetDef) {
                
                        List<FacetSlideDefinition> facetSlideDefinitions = new ArrayList<FacetSlideDefinition>();
                        
                        for(FacetSlideDefinitionType jaxbFacetSlideDef : jaxbFacetDef.getFacetSlideDefinition()){
                                long irDataRuleID = jaxbFacetSlideDef.getIRDataRuleID();
                                long irMetaDataRuleID = jaxbFacetSlideDef.getIRMetaDataRuleID();
                                long slideDefinitionID = jaxbFacetSlideDef.getSlideDefinitionID();
                                FacetSlideDefinition facetSlideDefinition = new FacetSlideDefinition(slideDefinitionID, irMetaDataRuleID, irDataRuleID);
                                facetSlideDefinitions.add(facetSlideDefinition);
                        }
                return facetSlideDefinitions;
        }

        /**
         * 
         * @param defType
         * @return
         * @throws Exception 
         */
        private Map<Long, CategoryFacetDefinition> convertCategoryFacetDefinitions(
                        IRDefinitionType defType) throws Exception {
                 List<CategoryFacetDefinitionType> jaxbCategoryFacetDefs = defType.getCategoryFacetDefinition();
                
                Map<Long, CategoryFacetDefinition> idCategoryFacetDefs = 
                        new TreeMap<Long, CategoryFacetDefinition>();
                
                for(CategoryFacetDefinitionType jaxbCategoryFacetDef : 
                        jaxbCategoryFacetDefs) {
                        
                        long categoryID = jaxbCategoryFacetDef.getCategoryID();
                        
                        CategoryFacetDefinition categoryFacetDef = 
                                new CategoryFacetDefinition(categoryID);
                        
                        
                        List<Long> facetIDs = jaxbCategoryFacetDef.getFacetDefinitionID();
                        
                        
                        for(Long facetID : facetIDs) {
                                categoryFacetDef.addFacetDefinition(facetDefinitions.get(facetID));
                        }
                        
                        idCategoryFacetDefs.put(new Long(categoryID), categoryFacetDef);
                }
                
                // Append parent's facets 
                // Go only one level for now
                // Categories need to be imported first
                
                for(Long categoryID : idCategoryFacetDefs.keySet()) {
                        Category category = this.getCategory(categoryID.longValue());
                        Category parentCategory = category.getParentCategory();
                        
                        if(parentCategory != null) {
                                long parentCategoryID = parentCategory.getID();
                                
                                CategoryFacetDefinition parentCategoryFacetDef = 
                                        idCategoryFacetDefs.get(new Long(parentCategoryID));
                                
                                if(parentCategoryFacetDef != null) {
                                        List<FacetDefinition> parentsFacetDefs = 
                                                parentCategoryFacetDef.getFacetDefinitions();
                                        
                                        if(parentsFacetDefs != null) {
                                                CategoryFacetDefinition categoryFacetDef = 
                                                        idCategoryFacetDefs.get(categoryID);
                                                
                                                categoryFacetDef.appendFacetDefinitions(
                                                                parentsFacetDefs);
                                        }
                                }
                        }
                }
                
                Utils.info("idCategoryFacetDefs=" + idCategoryFacetDefs);
                return idCategoryFacetDefs;
        }
        
        private FacetDefinition convertFacetDefinition(
                        FacetDefinitionType jaxbFacetDef) {
                long facetID = jaxbFacetDef.getID();
                String target = jaxbFacetDef.getTarget();
                FacetDefinition facetDefinition = new FacetDefinition(facetID, target);
                facetDefinition.setDescription(jaxbFacetDef.getDescription());
                facetDefinition.setFacetSlideDefinitions(convertFacetSlideDefinitions(jaxbFacetDef));
                return facetDefinition;
        }

        
        /**
         * 
         * @param jaxbFacetRuleDef
         * @return
         */
        /*
        private FacetRuleDefinition convertFacetRuleDefinition(
                        FacetRuleDefinitionType jaxbFacetRuleDef) {
                long facetDefID = jaxbFacetRuleDef.getFacetDefinitionID();
                long irDataRuleID = jaxbFacetRuleDef.getIRDataRuleID();
                
                FacetRuleDefinition facetRuleDef = new FacetRuleDefinition(facetDefID, 
                                irDataRuleID);
                
                facetRuleDef.setDescription(jaxbFacetRuleDef.getDescription());
                
                if(jaxbFacetRuleDef.getFeatureDefinitionID() != null) {
                        facetRuleDef.setFeatureDefinitionID(
                                        jaxbFacetRuleDef.getFeatureDefinitionID().longValue());
                }
                
                if(jaxbFacetRuleDef.getSlideDefinitionID() != null) {
                        facetRuleDef.setSlideDefinitionID(
                                        jaxbFacetRuleDef.getSlideDefinitionID().longValue());
                }
                
                return facetRuleDef;
        }
*/

        private void populateEnumValues(){
                // RE-VISIT - May not be optimal
                Map<Long, EnumValue> enumValuesMap = new TreeMap<Long, EnumValue>();
                for(Long datatypeDefID : datatypeDefinitions.keySet()) {
                        DatatypeDefinition datatypeDef = 
                                datatypeDefinitions.get(datatypeDefID);
                        
                        if(datatypeDef instanceof EnumDefinition) {
                                List<EnumValue> enumValues = 
                                        ((EnumDefinition) datatypeDef).getEnumValues();
                                
                                for(EnumValue enumValue : enumValues) {
                                        enumValuesMap.put(new Long(enumValue.getID()), 
                                                        enumValue);
                                }
                        }
                }
                this.enumValues = enumValuesMap;
        }
        
        
        /**
         * Returns Slide sequence for a category in the database
         * 
         * @return Map Null if Category-Slide definitions are not imported into 
         * definitions db 
         * (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, List<Long>> getCategorySlideSequence() throws Exception {              
                return this.categorySlideSequence;
        }

        
        /**
         * 
         * @param defType
         * @return
         */
        private Map<Long, List<Long>> convertCategorySlideSequence(
                        DefinitionType defType) {
                Map<Long, List<Long>> catSlideSeq = new HashMap<Long, List<Long>>();
                
                List<CategorySlideSequenceType> jaxbCatSlideSeqs = 
                        defType.getCategorySlideSequence();
                
                for(CategorySlideSequenceType jaxbCatSlideSeq : jaxbCatSlideSeqs) {
                        long catID = jaxbCatSlideSeq.getCategoryID();
                        List<Long> slideDefIDs = jaxbCatSlideSeq.getSlideDefinitionID();
                        
                        Long lCatID = new Long(catID);
                        catSlideSeq.put(lCatID, slideDefIDs);
                }
                
                return catSlideSeq;
        }

        
        /**
         * Given a category ID, returns all slide definition IDs in sequence 
         * provided by content editor
         * 
         * @param categoryID
         * @return List of Slide Definition IDs
         * @throws Exception
         */
        public List<Long> getCategorySlideSequence(long categoryID) throws Exception {  
                return this.categorySlideSequence.get(new Long(categoryID));
        }
        
        /**
         * Returns all Unit objects in the database
         * 
         * @return Map Null if units are not imported into definitions db 
         * (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, Unit> getUnits() throws Exception {
                return this.units;
        }
        

        /**
         * 
         * @param srcFile
         * @return
         * @throws Exception
         */
        private Object unmarshallSrcFile(String srcFile, String type) 
                throws Exception {
                
        JAXBContext jc = JAXBContext.newInstance("in.shop2020.metamodel.jaxb." +
                        type);
        
        // create an Unmarshaller
        Unmarshaller u = jc.createUnmarshaller();
        
        JAXBElement<?> element = (JAXBElement<?>)u.unmarshal(
                        new FileInputStream(srcFile));
        
        return element.getValue();
        }
        
        /**
         * 
         * @return Map
         */
        private Map<Long, Unit> convertUnits(DefinitionType defType) {
                
                Map<Long, Unit> allUnits = new HashMap<Long, Unit>();
                List<UnitType> jaxbUnits = defType.getUnit();
                Iterator<UnitType> it = jaxbUnits.iterator();
                
                while(it.hasNext()) {
                        UnitType jaxbUnit = it.next();
                        
                        Unit unit = new Unit(jaxbUnit.getID());
                        unit.setDescription(jaxbUnit.getDescription());
                        unit.setFullForm(jaxbUnit.getFullform());
                        unit.setShortForm(jaxbUnit.getShortform());
                        Utils.info("unit=" + unit);
                
                        allUnits.put(new Long(jaxbUnit.getID()), unit);
                }
                
                return allUnits;
        }

        
        /**
         * Resolves Unit ID into Unit object
         * 
         * @param unitID Unit ID
         * @return Unit
         * @throws Exception 
         */
        public Unit getUnit(long unitID) throws Exception {             
                return this.units.get(new Long(unitID));
        }

        /**
         * Returns all DatatypeDefintion object in database
         * 
         * @return the datatypeDefinitions List of DatatypeDefinition objects
         * @throws Exception 
         */
        public Map<Long, DatatypeDefinition> getDatatypeDefinitions(){
                return this.datatypeDefinitions;
        }

        
        /**
         * 
         * @param defType
         * @return
         */
        private Map<Long, DatatypeDefinition> convertDatatypeDefinition(DefinitionType defType) {
                
                Map<Long, DatatypeDefinition> defs = new HashMap<Long, DatatypeDefinition>();
                
                List<DatatypeDefinitionType> jaxbDefs = defType.getDatatypeDefinition();
                Iterator<DatatypeDefinitionType> it = jaxbDefs.iterator();
                
                while(it.hasNext()) {
                        DatatypeDefinitionType jaxbDef = it.next();
                        
                        DatatypeDefinition def = null;
                        CompositeDefinitionType compositeDefType = jaxbDef.getCompositeDefinition();

                        EnumDefinitionType enumDefType = jaxbDef.getEnumDefinition();
                        
                        // Composite data type
                        if(compositeDefType != null) {
                                CompositeDefinition compDef = new CompositeDefinition(jaxbDef.getID(), jaxbDef.getName(), compositeDefType.getSeparator());
                                
                                List<CompositePartDefinitionType> jaxbPartDefs = compositeDefType.getCompositePartDefinition();
                                
                                Iterator<CompositePartDefinitionType> itPartDefs = jaxbPartDefs.iterator();
                                
                                // Collect parts
                                while(itPartDefs.hasNext()) {
                                        CompositePartDefinitionType jaxbPartDef = itPartDefs.next();
                                        CompositePartDefinition partDef = this.convertCompositePartDefinition(jaxbPartDef);
                                        
                                        compDef.addCompositePartDefinition(partDef);
                                }
                                
                                def = compDef;
                        }
                        
                        // Enumerated values
                        else if(enumDefType != null) {
                                EnumDefinition enumDef = new EnumDefinition(jaxbDef.getID(), 
                                                jaxbDef.getName());
                                
                                List<EnumValueType> jaxbEnumValues = 
                                        enumDefType.getEnumValue();
                                        
                                Iterator<EnumValueType> itEnumValues = 
                                        jaxbEnumValues.iterator();
                                
                                // Collect individual value
                                while(itEnumValues.hasNext()) {
                                        EnumValueType jaxbEnumValue = itEnumValues.next();
                                        EnumValue enumValue = 
                                                this.convertEnumValueDefinition(jaxbEnumValue);
                                        
                                        enumDef.addEnumValue(enumValue);
                                }
                                
                                def = enumDef;
                        }
                        
                        // Primitive
                        else {
                                def = new DatatypeDefinition(jaxbDef.getID(), 
                                                jaxbDef.getName());
                        }
                        
                        def.setDescription(jaxbDef.getDescription());
                        Utils.info("def=" + def);
                        
                        defs.put(new Long(jaxbDef.getID()), def);
                }
                
                return defs;
        }

        /**
         * 
         * @param jaxbPartDef
         * @return CompositePartDefinition
         */
        private CompositePartDefinition convertCompositePartDefinition(
                        CompositePartDefinitionType jaxbPartDef) {
                
                CompositePartDefinition partDef = new CompositePartDefinition(
                                jaxbPartDef.getLabel(), jaxbPartDef.getDatatypeDefinitionID(), 
                                jaxbPartDef.getUnitID());
                
                partDef.setDescription(jaxbPartDef.getDescription());
                
                return partDef;
        }

        /**
         * Resolves Datatype Definition ID into DatetypeDefinition object
         * 
         * @param unitID Unit ID
         * @return Unit
         * @throws Exception 
         */
        public DatatypeDefinition getDatatypeDefinition(long id) throws Exception {
                
                // Initialize 
                if(this.datatypeDefinitions == null) {
                        this.getDatatypeDefinitions();
                }
                
                return this.datatypeDefinitions.get(new Long(id));
        }

        /**
         * 
         * @param jaxbEnumValue
         * @return EnumValue
         */
        private EnumValue convertEnumValueDefinition(EnumValueType jaxbEnumValue) {
                
                EnumValue enumValue = new EnumValue(jaxbEnumValue.getID(), 
                                jaxbEnumValue.getValue());
                if(jaxbEnumValue.getHelpDocDefinitionID() != null){
                    enumValue.setHelpDocDefinitionID(jaxbEnumValue.getHelpDocDefinitionID()); 
                }
                return enumValue;
        }
        /**
         * Returns EnumValue ID for datatype definition ID and enum value string 
         * to match. Match is case insensitive
         * 
         * @param datatypeDefID DatatypeDefinition ID
         * @param value query enum value string
         * @return long enumValueID - "-1" if not found
         * @throws Exception 
         */
        public long getEnumValueID(long datatypeDefID, String value) 
                throws Exception {
                long enumValueID = -1L;
                
                // Let the callers catch ClassCastException
                EnumDefinition enumDef = 
                        (EnumDefinition)this.getDatatypeDefinition(datatypeDefID);
                
                List<EnumValue> enumValues = enumDef.getEnumValues();
                for(EnumValue enumValue : enumValues) {
                        if(value.equalsIgnoreCase(enumValue.getValue())) {
                                enumValueID = enumValue.getID();
                                break;
                        }
                }
                
                return enumValueID;
        }
        
        /**
         * Returns all category objects in the database
         * 
         * @return the categories
         * @throws Exception 
         */
        public Map<Long, Category> getCategories() {
                return this.categories;
        }
        
        
        /**
         * 
         * @param defType
         * @param catMap
         * @return
         */
        private Category convertCategories(DefinitionType defType, 
                        Map<Long, Category> catMap, String srcFile) {
                
                List<CategoryType> jaxbCats = defType.getCategory();
                Iterator<CategoryType> it = jaxbCats.iterator();
                
                // Get root category
                CategoryType jaxbCat = it.next();
                if(jaxbCat == null) {
                        Utils.info("Invalid file: " + srcFile);
                        return null;
                }
                
                Category root = this.convertCategoryType(jaxbCat, null, catMap);
                return root;
        }
        
        
        /**
         * 
         * @param jaxbCat
         * @param parentCat
         * @param catMap
         * @return
         */
        @SuppressWarnings("unchecked")
        private Category convertCategoryType(CategoryType jaxbCat, 
                        Category parentCat, Map<Long, Category> catMap) {
                
                Category cat = new Category(jaxbCat.getID());
                cat.setLabel(jaxbCat.getName());
                cat.setDescription(jaxbCat.getDescription());
                if(parentCat != null) {
                        cat.setParentCategory(parentCat);
                        
                        // Copy parent's category-slide definitions
                        ArrayList<CategorySlideDefinition> parentCSDef = 
                                (ArrayList<CategorySlideDefinition>) 
                                parentCat.getCategorySlideDefintions();
                        
                        if(parentCSDef != null) {
                                cat.setCategorySlideDefintions(
                                        (List<CategorySlideDefinition>) parentCSDef.clone());
                        }
                }
                
                // Category Slide Definition
                List<CategorySlideDefinitionType> jaxbDefs = 
                        jaxbCat.getCategorySlideDefinition();
                
                Iterator<CategorySlideDefinitionType> it = jaxbDefs.iterator();
                while(it.hasNext()) {
                        CategorySlideDefinitionType jaxbDef = it.next();
                        CategorySlideDefinition catSlideDef 
                        = this.convertCategorySlideDefinitionType(jaxbCat.getID(), jaxbDef);
                        
                        cat.addCategorySlideDefintion(catSlideDef);
                }
                
                // Children
                List<CategoryType> jaxbChildren = jaxbCat.getChildCategory();
                //Utils.info("jaxbChildren.size: " + jaxbChildren.size());
                
                Iterator<CategoryType> itChildren = jaxbChildren.iterator();
                while(itChildren.hasNext()) {
                        CategoryType jaxbChildCat = itChildren.next();
                        Category childCat = this.convertCategoryType(jaxbChildCat, cat, 
                                        catMap);
                        cat.addChild(childCat);
                }
                
                //FIXME put debug messages
                //Utils.info("Parent cat: " + cat);
                // DEBUG ONLY
                Utils.info("####### Cat ID: " + cat.getID());
                if(cat.getCategorySlideDefintions() != null) {
                        for(CategorySlideDefinition csd : cat.getCategorySlideDefintions()){
                                Utils.info("####### SlideDefintionID=" + csd.getSlideDefintionID());
                        }
                }
                
                catMap.put(new Long(jaxbCat.getID()), cat);
                return cat;
        }
        
        /**
         * 
         * @param categoryID
         * @param jaxbDef
         * @return
         */
        private CategorySlideDefinition convertCategorySlideDefinitionType(
                        long categoryID, CategorySlideDefinitionType jaxbDef) {
                
                CategorySlideDefinition catSlideDef = new CategorySlideDefinition(
                                jaxbDef.getSlideDefinitionID());
                
                catSlideDef.setDescription(jaxbDef.getDescription());
                
                EditorialImportanceType jaxbEdImp = jaxbDef.getEditorialImportance();
                EditorialImportance edImp = this.convertEditorialImportance(jaxbEdImp);
                catSlideDef.setEditorialImportance(edImp);
                
                return catSlideDef;
        }
        
        /**
         * 
         * @param jaxbEdImp
         * @return EditorialImportance
         */
        private EditorialImportance convertEditorialImportance(
                        EditorialImportanceType jaxbEdImp) {
                
                String strEdImp = jaxbEdImp.value();
                EditorialImportance edImp = null;
                
                if(strEdImp.equals("Mandatory"))
                        edImp = EditorialImportance.MANDATORY;
                else if(strEdImp.equals("Optional"))
                        edImp = EditorialImportance.OPTIONAL;
                else 
                        edImp = EditorialImportance.RECOMMENDED;
                
                return edImp;
        }

        
        /**
         * Resolves Category ID into Category object
         * 
         * @param categoryID Category ID
         * @return Category
         * @throws Exception 
         */
        public Category getCategory(long categoryID) {
                return this.categories.get(new Long(categoryID));
        }
        
        /**
         * Returns expanded Category object. All numeric identifiers are resolved 
         * into detailed objects
         * 
         * @param categoryID
         * @return ExpandedCategory
         * @throws Exception
         */
        public ExpandedCategory getExpandedCategory(long categoryID) 
                throws Exception {
                Category category = this.getCategory(categoryID);
                
                ExpandedCategory expCategory = new ExpandedCategory(category);
                
                return expCategory;
        }
        
        /**
         * Returns all children categories for a Category ID
         * 
         * @param categoryID
         * @return List<Category> Children Categories
         * @throws Exception
         */
        public List<Category> getChildrenCategories(long categoryID){
                return this.categories.get(new Long(categoryID)).getChildrenCategory();
        }
        
        /**
         * Returns all CategorySlideDefinition objects for a Category ID
         * 
         * @param categoryID Category ID
         * @return List<CategorySlideDefinition> 
         * @throws Exception 
         */
        public List<CategorySlideDefinition> getCategorySlideDefinitions(
                        long categoryID) throws Exception {
                Category category = this.getCategory(categoryID);
                
                return category.getCategorySlideDefintions();
        }
        
        /**
         * Returns All SlideDefinition objects in database
         * 
         * @return the slideDefinitions
         * @throws Exception 
         */
        public Map<Long, SlideDefinition> getSlideDefinitions(){
                return this.slideDefinitions;
        }
        
        /**
         * 
         * @return Map
         */
        private Map<Long, SlideDefinition> convertSlideDefinitions(
                        DefinitionType defType) {
                
                Map<Long, SlideDefinition> defs = 
                        new HashMap<Long, SlideDefinition>();
                
                List<SlideDefinitionType> jaxbDefs = defType.getSlideDefinition();
                Iterator<SlideDefinitionType> itjaxbDefs = jaxbDefs.iterator();
                
                // Slide definitions
                while(itjaxbDefs.hasNext()) {
                        SlideDefinitionType jaxbDef = itjaxbDefs.next();
                        
                        Utils.info("Slide label=" + jaxbDef.getLabel());
                        SlideDefinition def = new SlideDefinition(jaxbDef.getID(),
                                        jaxbDef.getLabel());
                        def.setDescription(jaxbDef.getDescription());
                        
                        Long helpDocDefID = jaxbDef.getHelpDocDefinitionID();
            if(helpDocDefID != null) {
                def.setHelpDocDefinitionID(helpDocDefID.longValue());
            }
            
                        // Children Slides
                        Utils.info("jaxbDef.getChildSlideID=" + jaxbDef.getChildSlideID());
                        def.setChildrenSlideDefinitionIDs(jaxbDef.getChildSlideID());
                        
                        // Slide Feature Definition
                        List<SlideFeatureDefinitionType> jaxbSlideFeatureDefs = 
                                jaxbDef.getSlideFeatureDefinition();
                        
                        if(jaxbSlideFeatureDefs != null) {
                                def.setSlideFeatureDefinitions((
                                                this.convertSlideFeatureDefinitions(
                                                                jaxbSlideFeatureDefs)));
                        }
                        Utils.info("def=" + def);
                        
                        defs.put(new Long(jaxbDef.getID()), def);
                }
                        
                return defs;
        }

        
        /**
     * 
     * @return Map
     */
    private Map<Long, HelpDocDefinition> convertHelpDocDefinitions(DefinitionType defType) {
        
        Map<Long, HelpDocDefinition> defs = 
            new HashMap<Long, HelpDocDefinition>();
        
        List<HelpDocDefinitionType> jaxbDefs = defType.getHelpDocDefinition();
        Iterator<HelpDocDefinitionType> itjaxbDefs = jaxbDefs.iterator();
        
        // Help Doc definitions
        while(itjaxbDefs.hasNext()) {
            HelpDocDefinitionType jaxbDef = itjaxbDefs.next();
            
            Utils.info("Helo doc name is =" + jaxbDef.getName());
            HelpDocDefinition def = new HelpDocDefinition(jaxbDef.getID(), jaxbDef.getName());
            
            Utils.info("def=" + def);
            
            defs.put(new Long(jaxbDef.getID()), def);
        }
            
        return defs;
    }
        
        
        /**
         * 
         * @param jaxbDefs
         * @return List<SlideFeatureDefinition>
         */
        private List<SlideFeatureDefinition> convertSlideFeatureDefinitions(
                        List<SlideFeatureDefinitionType> jaxbDefs) {
                
                List<SlideFeatureDefinition> defs = 
                        new ArrayList<SlideFeatureDefinition>();
                
                Iterator<SlideFeatureDefinitionType> itjaxbDefs = jaxbDefs.iterator();
                
                // Slide-feature definitions
                while(itjaxbDefs.hasNext()) {
                        SlideFeatureDefinitionType jaxbDef = itjaxbDefs.next();
                        SlideFeatureDefinition def = new SlideFeatureDefinition(
                                        jaxbDef.getFeatureDefinitionID());
                        
                        def.setEditorialImportance(this.convertEditorialImportance(
                                        jaxbDef.getEditorialImportance()));
                        
                        def.setDescription(jaxbDef.getDescription());
                        
                        defs.add(def);
                }
                
                return defs;
        }

        
        /**
         * Resolves SlideDefinition ID into SlideDefinition object
         * 
         * @param id
         * @return SlideDefinition
         * @throws Exception
         */
        public SlideDefinition getSlideDefinition(long id) throws Exception {
                
                // Initialize 
                if(this.slideDefinitions == null) {
                        this.getSlideDefinitions();
                }
                
                return this.slideDefinitions.get(new Long(id));
        }
        
        /**
         * 
         * @param slideID
         * @return ExpandedSlideDefinition 
         * @throws Exception 
         */
        public ExpandedSlideDefinition getExpandedSlideDefinition(long slideID) 
                throws Exception {
                SlideDefinition slideDef = this.getSlideDefinition(slideID);
                
                return new ExpandedSlideDefinition(slideDef);
        }
        
        /**
         * Returns SlideDefinition objects for a category and matching slide label
         * 
         * @param label
         * @return List<SlideDefinition>
         * @throws Exception
         */
        public List<SlideDefinition> getSlideDefinitions(long categoryID, 
                        String label) throws Exception {

                // RE-VISIT
                // May be we need a new data structure, category id to slide definitions
                // for now
                List<SlideDefinition> matchingSlides = new ArrayList<SlideDefinition>();
                
                List<CategorySlideDefinition> csDefs = this.getCategorySlideDefinitions(
                                categoryID);
                
                for(CategorySlideDefinition csDef : csDefs) {
                        SlideDefinition sDef = this.getSlideDefinition(
                                        csDef.getSlideDefintionID());
                        
                        if(sDef.getLabel().equalsIgnoreCase(label)) {
                                matchingSlides.add(sDef);
                        }
                }
                
                return matchingSlides;
        }
        
        /**
         * Resolves Category ID into Category object
         * 
         * @param categoryID
         * @return List<SlideDefinition> 
         * @throws Exception
         */
        public List<SlideDefinition> getSlideDefinitions(long categoryID) 
                throws Exception {

                // RE-VISIT
                // May be we need a new data structure, category id to slide definitions
                // for now
                List<SlideDefinition> matchingSlides = new ArrayList<SlideDefinition>();
                
                List<CategorySlideDefinition> csDefs = this.getCategorySlideDefinitions(
                                categoryID);
                
                for(CategorySlideDefinition csDef : csDefs) {
                        SlideDefinition sDef = this.getSlideDefinition(
                                        csDef.getSlideDefintionID());
                        
                        matchingSlides.add(sDef);
                }
                
                return matchingSlides;
        }
        
        /**
         * Returns list of SlideDefinition objects for a category and editorial 
         * importance value
         * 
         * @param categoryID
         * @param EditorialImportance imp
         * @return List<SlideDefinition>
         * @throws Exception 
         */
        public List<SlideDefinition> getSlides(long categoryID, 
                        EditorialImportance imp) 
                throws Exception {
                
                List<CategorySlideDefinition> catSlideDefs = 
                        this.getCategorySlideDefinitions(categoryID);
                
                Iterator<CategorySlideDefinition> itCatSlideDefs = 
                        catSlideDefs.iterator();
                
                List<SlideDefinition> slideDefs = new ArrayList<SlideDefinition>();
                while(itCatSlideDefs.hasNext()) {
                        CategorySlideDefinition catSlideDef = itCatSlideDefs.next();
                        if(catSlideDef.getEditorialImportance() == imp) {
                                long slideDefID = catSlideDef.getSlideDefintionID();
                                slideDefs.add(this.getSlideDefinition(slideDefID));
                        }
                }
                return slideDefs;
        }
        
        /**
         * Returns all FeatureDefinition object in database
         * 
         * @return Map<Long, FeatureDefinition>
         * @throws Exception
         */
        public Map<Long, FeatureDefinition> getFeatureDefinitions(){
                return this.featureDefinitions;
        }
        
        
        /**
         * 
         * @param defType
         * @return
         */
        private Map<Long, FeatureDefinition> convertFeatureDefinitions(
                        DefinitionType defType) {
                
                Map<Long, FeatureDefinition> defs = 
                        new HashMap<Long, FeatureDefinition>();
                
                List<FeatureDefinitionType> jaxbDefs = defType.getFeatureDefinition();
                Iterator<FeatureDefinitionType> itjaxbDefs = jaxbDefs.iterator();
                
                // Feature definitions
                while(itjaxbDefs.hasNext()) {
                        FeatureDefinitionType jaxbDef = itjaxbDefs.next();
                        Utils.info("******"+ jaxbDef.getID());
                        
                        //Utils.info("Feature label=" + jaxbDef.getLabel());
                        FeatureDefinition def = new FeatureDefinition(jaxbDef.getID(),
                                        jaxbDef.getLabel());
                        def.setAllowsBlank(jaxbDef.isCanbeBlank());
                        def.setDescription(jaxbDef.getDescription());
                        
                        // Bullet Definition
                        BulletDefinitionType jaxbBulletDef = jaxbDef.getBulletDefinition();
                        if(jaxbBulletDef != null) {
                                def.setBulletDefinition(this.convertBulletDefinition(
                                                jaxbBulletDef));
                        }
                        
                        Long normRuleDefID = jaxbDef.getNormalizationRuleDefinitionID();
                        if(normRuleDefID != null) {
                                def.setNormalizationRuleDefinitionID(normRuleDefID.longValue());
                        }
                        Utils.info("def=" + def);
                        
                        Long helpDocDefID = jaxbDef.getHelpDocDefinitionID();
            if(helpDocDefID != null) {
                def.setHelpDocDefinitionID(helpDocDefID.longValue());
            }
            Utils.info("def=" + def);
            
                        defs.put(new Long(jaxbDef.getID()), def);
                }
                        
                return defs;
        }

        
        /**
         * 
         * @param jaxbDef BulletDefinitionType
         * @return BulletDefinition
         */
        private BulletDefinition convertBulletDefinition(
                        BulletDefinitionType jaxbDef) {
                
                BulletDefinition def = new BulletDefinition(
                                jaxbDef.getDatatypeDefinitionID());
                
                List<Long> unitIDs = jaxbDef.getUnitID();
                if(unitIDs != null && !unitIDs.isEmpty()) {
                        def.setUnitIDs(unitIDs);
                }
                Utils.info("jaxbDef.isIsMultivalue=" + jaxbDef.isIsMultivalue());
                
                def.setMultivalue(jaxbDef.isIsMultivalue());
                def.setLearned(jaxbDef.isIsLearned());
                def.setDescription(jaxbDef.getDescription());
                
                return def;
        }

        
        /**
         * Returns all FeatureDefinition objects for a slide
         * 
         * @param slideID
         * @return List<FeatureDefinition> 
         * @throws Exception
         */
        public List<FeatureDefinition> getFeatureDefinitions(long slideID) 
                throws Exception {
                List<FeatureDefinition> featureDefs = 
                        new ArrayList<FeatureDefinition>();
                
                SlideDefinition slideDef = this.getSlideDefinition(slideID);
                List<SlideFeatureDefinition> slideFeatureDefs = 
                        slideDef.getSlideFeatureDefinitions();
                
                for(int i=0; i<slideFeatureDefs.size(); i++) {
                        featureDefs.add(this.getFeatureDefinition(
                                        slideFeatureDefs.get(i).getFeatureDefintionID()));
                }
                
                return featureDefs;
        }
        
        /**
         * Returns list of FeatureDefinition objects for a slide given editorial 
         * importance
         * 
         * @param slideID
         * @param imp Editorial Importance enum object
         * @return List<FeatureDefinition>
         * @throws Exception
         */
        public List<FeatureDefinition> getFeatureDefinitions(long slideID, 
                        EditorialImportance imp)  throws Exception {
                List<FeatureDefinition> featureDefs = 
                        new ArrayList<FeatureDefinition>();
                
                SlideDefinition slideDef = this.getSlideDefinition(slideID);
                List<SlideFeatureDefinition> slideFeatureDefs = 
                        slideDef.getSlideFeatureDefinitions();
                
                for(SlideFeatureDefinition slideFeatureDef : slideFeatureDefs) {
                        if(slideFeatureDef.getEditorialImportance() == imp) {
                                featureDefs.add(this.getFeatureDefinition(
                                                slideFeatureDef.getFeatureDefintionID()));
                        }
                }
                
                return featureDefs;
        }
        
        /**
         * Resolves Feature Definition ID into FeatureDefinition object
         * 
         * @param id Feature Definition ID 
         * @return FeatureDefinition
         * @throws Exception
         */
        public FeatureDefinition getFeatureDefinition(long id) throws Exception {
                
                // Initialize 
                if(this.featureDefinitions == null) {
                        this.getFeatureDefinitions();
                }
                
                return this.featureDefinitions.get(new Long(id));
        }       

        /**
         * Returns matching FeatureDefinition object for slide ID and feature label.
         * Label matching is case insensitive.
         * 
         * @param slideID Slide ID
         * @param featureLabel label to match, case is ignored
         * @return FeatureDefinition 
         * @throws Exception
         */
        public FeatureDefinition getFeatureDefinition(long slideID, 
                        String featureLabel) throws Exception {
                FeatureDefinition featureDef = null;
                
                SlideDefinition slideDef = this.getSlideDefinition(slideID);
                for(SlideFeatureDefinition slideFeatureDef : 
                        slideDef.getSlideFeatureDefinitions()) {
                        
                        long featureDefID = slideFeatureDef.getFeatureDefintionID();
                        
                        FeatureDefinition thisFeatureDef = this.getFeatureDefinition(
                                        featureDefID);
                        
                        if(featureLabel.equalsIgnoreCase(thisFeatureDef.getLabel())) {
                                featureDef = thisFeatureDef;
                        }
                }
                
                return featureDef;
        }

        /**
         * Returns all EnumValue objects in the database
         * 
         * @return the enumValues
         * @throws Exception 
         */
        public Map<Long, EnumValue> getEnumValues() throws Exception {
                return this.enumValues;
        }
        
        
        /**
         * Resolves Enum value ID into EnumValue object
         * 
         * @param enumValueID
         * @return EnumValue
         * @throws Exception
         */
        public EnumValue getEnumValue(long enumValueID) throws Exception {
                return this.enumValues.get(new Long(enumValueID));
        }

        /**
         * Returns all FacetDefinition objects in the database
         * 
         * @return Map Null if facet definitions are not imported into definitions 
         * db (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, FacetDefinition> getFacetDefinitions(){
                return this.facetDefinitions;
        }
        
        /**
         * Get List of Facets for a given slide.
         * 
         * @return
         */
        public Map<Long, List<FacetDefinition>> getSlideFacetDefinitions(){
                return slideFacetDefinitions;
        }
        /**
         * Resolves Facet Definition ID into FacetDefinition object
         * 
         * @param facetDefinitionID
         * @return FacetDefinition
         * @throws Exception
         */
        public FacetDefinition getFacetDefinition(long facetDefinitionID) 
                throws Exception {
                
                if(this.facetDefinitions == null) {
                        this.getFacetDefinitions();
                }
                
                return this.facetDefinitions.get(new Long(facetDefinitionID));
        }
        
        /**
         * Utility method to get Expanded version of ExpandedFacetDefinition object 
         * 
         * @param facetDefinitionID
         * @return ExpandedFacetDefinition
         * @throws Exception
         */
        /*
        public ExpandedFacetDefinition getExpandedFacetDefinition(
                        long facetDefinitionID) throws Exception {
                
                FacetDefinition facetDefinition = 
                        this.getFacetDefinition(facetDefinitionID);
                
                ExpandedFacetDefinition expFacetDefinition = 
                        new ExpandedFacetDefinition(facetDefinition);
                
                return expFacetDefinition;
        }
        */
        /**
         * Returns all CategoryFacetDefinition objects in the database
         * 
         * @return Map Null if category facet definitions are not imported into 
         * definitions db (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, CategoryFacetDefinition> getCategoryFacetDefinitions(){
                return this.categoryFacetDefinitions;
        }
        
        /**
         * Resolves Category-Facet Definition ID into CategoryFacetDefinition object
         * 
         * @param categoryID
         * @return CategoryFacetDefinition
         * @throws Exception
         */
        public CategoryFacetDefinition getCategoryFacetDefinition(long categoryID){
                return this.categoryFacetDefinitions.get(new Long(categoryID));
        }
        
        
        /**
         * Utility method to get Expanded version of CategoryFacetDefinition object 
         * 
         * @param categoryID
         * @return ExpandedCategoryFacetDefinition
         * @throws Exception
         */
        public ExpandedCategoryFacetDefinition getExpandedCategoryFacetDefinition(
                        long categoryID) throws Exception  {
                CategoryFacetDefinition categoryFacetDef = 
                        this.getCategoryFacetDefinition(categoryID);
                
                ExpandedCategoryFacetDefinition expCategoryFacetDef = 
                        new ExpandedCategoryFacetDefinition(categoryFacetDef);
                
                return expCategoryFacetDef;
        }
        
        /**
         * Returns all IR Data RuleDefintion objects in the database
         * 
         * @return Map Null if IR data rule definitions are not imported into 
         * definitions db (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, RuleDefinition> getIrDataRuleDefinitions(){
                return this.irDataRuleDefinitions;
        }
        
        /**
         * Resolves IR Data Rule Definition ID into RuleDefinition object
         * 
         * @param irDataRuleDefinitionID
         * @return RuleDefinition
         * @throws Exception
         */
        public RuleDefinition getIrDataRuleDefinition(long irDataRuleDefinitionID){
                return this.irDataRuleDefinitions.get(new Long(irDataRuleDefinitionID));
        }
        
        /**
         * Returns all IR Meta Data RuleDefintion objects in the database
         * 
         * @return Map Null if IR meta-data rule definitions are not imported into 
         * definitions db (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, RuleDefinition> getIrMetaDataRuleDefinitions(){
                return this.irMetaDataRuleDefinitions;
        }
        
        /**
         * Resolves IR Meta Data Rule Definition ID into RuleDefinition object
         * 
         * @param irMetaDataRuleDefinitionID
         * @return RuleDefinition
         * @throws Exception
         */
        public RuleDefinition getIrMetaDataRuleDefinition(long irMetaDataRuleDefinitionID) {
                return this.irMetaDataRuleDefinitions.get(new Long(irMetaDataRuleDefinitionID));
        }
        
        /**
         * Returns all Comparison RuleDefintion objects in the database
         * 
         * @return Map Null if Comparison rule definitions are not imported into 
         * definitions db (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, CMPRuleDefinition> getComparisonRuleDefinitions(){
                return this.cmpRuleDefinitions;
        }
        
        /**
         * Resolves IR Data Rule Definition ID into RuleDefinition object
         * 
         * @param cmpRuleDefinitionID
         * @return CMPRuleDefinition
         * @throws Exception
         */
        public CMPRuleDefinition getComparisonRuleDefinition(long cmpRuleDefinitionID) {
                return this.cmpRuleDefinitions.get(new Long(cmpRuleDefinitionID));
        }

        
        /**
         * Returns all ComparisonSlideRuleDefintion objects in the database
         * 
         * @return Map Null if Comparison slide-rule definitions are not imported 
         * into definitions db (serialized java objects)
         * 
         * @throws Exception 
         */
        public Map<Long, CMPSlideRuleDefinition> getComparisonSlideRuleDefinitions() {
                return this.cmpSlideRuleDefinitions;
        }
        
        /**
         * Resolves Category ID into List of CMPSlideRuleDefinition object
         * 
         * @param categoryID
         * @return List<CMPSlideRuleDefinition> 
         * @throws Exception
         */
        public CMPSlideRuleDefinition getComparisonSlideRuleDefinition(long slideDefinitionID) {
                return this.cmpSlideRuleDefinitions.get(new Long(slideDefinitionID));
        }

        
        /**
         * Resolves Slide Definition ID into ExpandedCMPSlideRuleDefinition object
         * 
         * @param categoryID
         * @return ExpandedCMPSlideRuleDefinition 
         * @throws Exception
         */
        public ExpandedCMPSlideRuleDefinition getExpandedComparisonSlideRuleDefinition(long slideDefinitionID) throws Exception{
                Utils.info("slideDefinitionID=" + slideDefinitionID);
                
                CMPSlideRuleDefinition cmpSlideRuleDef = this.getComparisonSlideRuleDefinition(slideDefinitionID);
                
                if(cmpSlideRuleDef == null) {
                        return null;
                }
                
                ExpandedCMPSlideRuleDefinition expDef = new ExpandedCMPSlideRuleDefinition(cmpSlideRuleDef);
                return expDef;
        }

        
        /**
         * Returns all ComparisonSlideRuleDefintion objects in the database
         * 
         * @return Map Null if Comparison slide-rule definitions are not imported 
         * into definitions db (serialized java objects)
         * 
         * @throws Exception 
         */
        
        public Map<Long, List<CMPBucketDefinition>> getComparisonBucketDefinitions(){
                return this.cmpBucketDefinitions;
        }
        
        /**
         * Resolves Category ID into List of CMPBucketDefinition object
         * 
         * @param categoryID
         * @return List<CMPBucketDefinition> 
         * @throws Exception
         */
        public List<CMPBucketDefinition> getComparisonBucketDefinitions(long categoryID) {
                return this.cmpBucketDefinitions.get(new Long(categoryID));
        }
        
        /**
         * Resolve comparison bucket name for a slide in a particular category
         * 
         * @param categoryID
         * @param slideDefintionID
         * @return Bucket Name if found else Null
         * @throws Exception 
         */
        public String getComparisonBucketName(long categoryID, 
                        long slideDefinitionID) throws Exception {
                List<CMPBucketDefinition> cmpBuckets = 
                        this.getComparisonBucketDefinitions(categoryID);
                if(cmpBuckets == null){
                    return null;
                }
                for (CMPBucketDefinition cmpBucket : cmpBuckets) {
                        List<Long> slideDefinitionIDs = cmpBucket.getSlideDefinitionIDs();
                        
                        if(slideDefinitionIDs.contains(new Long(slideDefinitionID))) {
                                return cmpBucket.getName();
                        }
                }
                return null;
        }
        
        /**
         * Returns list of facet definition IDs for given category ID
         * 
         * @param categoryID
         * @return list of facet definition IDs
         * @throws Exception 
         */
        public List<Long> getFacetDefinitionIDs(long categoryID) throws Exception {
                List<Long> facetDefIDs = new ArrayList<Long>();
                
                CategoryFacetDefinition categoryFacetDef = 
                        this.getCategoryFacetDefinition(categoryID);
                if(categoryFacetDef == null)
                        return null;
                List<FacetDefinition> facetDefs = 
                        categoryFacetDef.getFacetDefinitions();
                
                for(FacetDefinition facetDef : facetDefs) {
                        facetDefIDs.add(new Long(facetDef.getID()));
                }
                
                return facetDefIDs;
        }
        
        /**
         * Returns list of feature definition IDs for given category ID
         * 
         * @param categoryID
         * @return list of feature definition IDs
         * @throws Exception 
         */
        public List<Long> getFeatureDefinitionIDs(long categoryID) 
                throws Exception {
                
                List<Long> featureDefIDs = new ArrayList<Long>();
                
                List<SlideDefinition> slideDefs = this.getSlideDefinitions(categoryID);
                
                for(SlideDefinition slideDef : slideDefs) {
                        List<Long> slideFeatureDefIDs = 
                                this.getFeatureDefintionIDs(slideDef);
                        
                        featureDefIDs.addAll(slideFeatureDefIDs);
                }
                
                return featureDefIDs;
        }
        
        /**
         * Returns list of feature definition IDs for given slide definition ID
         * 
         * @param slideDef
         * @return list of feature definition IDs
         */
        public List<Long> getFeatureDefintionIDs(SlideDefinition slideDef) {
                List<Long> featureDefIDs = new ArrayList<Long>();
                
                List<SlideFeatureDefinition> slideFeatureDefs = 
                        slideDef.getSlideFeatureDefinitions();
                
                for(SlideFeatureDefinition slideFeatureDef : slideFeatureDefs) {
                        featureDefIDs.add(new Long(slideFeatureDef.getFeatureDefintionID()));
                }
                
                return featureDefIDs;
        }
        
        /**
         * 
         * @param borrowedSlideDefID
         * @return
         * @throws Exception 
         */
        public boolean isValidSlideDefinitionID(long borrowedSlideDefID) 
                throws Exception {
                this.getSlideDefinitions();
                
                return this.slideDefinitions.containsKey(new Long(borrowedSlideDefID));
        }
        
        /**
         * Returns Facet-Rule definition object defined for a category and 
         * slide definition
         * 
         * @param borrowedCategoryID
         * @param slideDefID
         * @return FacetRuleDefinition 
         * @throws Exception 
         */
        /*
        public FacetRuleDefinition getFacetRuleDefinitionForSlide(long categoryID,
                        long slideDefinitionID) throws Exception {
                CategoryFacetDefinition categoryFacetDef = 
                        this.getCategoryFacetDefinition(categoryID);
                //FIXME Quick fix. Need to investigate
                if(categoryFacetDef == null){
                        return null;
                }
                List<FacetRuleDefinition> facetRuleDefs = 
                        categoryFacetDef.getFacetRuleDefinitions();
                
                for(FacetRuleDefinition facetRuleDef : facetRuleDefs) {
                        if(facetRuleDef.getSlideDefinitionID() == slideDefinitionID) {
                                return facetRuleDef;
                        }
                }
                
                return null;
        }
        */
        /**
         * Returns Facet-Rule definition object defined for a category and 
         * feature definition
         * 
         * @param categoryID
         * @param featureDefinitionID
         * @return FacetRuleDefinition
         * @throws Exception
         */
        
/*
        public FacetRuleDefinition getFacetRuleDefinitionForFeature(long categoryID,
                        long featureDefinitionID) throws Exception {
                CategoryFacetDefinition categoryFacetDef = 
                        this.getCategoryFacetDefinition(categoryID);
                if(categoryFacetDef == null){
                        return null;
                }
                List<FacetRuleDefinition> facetRuleDefs = 
                        categoryFacetDef.getFacetRuleDefinitions();
                
                for(FacetRuleDefinition facetRuleDef : facetRuleDefs) {
                        if(facetRuleDef.getFeatureDefinitionID() == featureDefinitionID) {
                                return facetRuleDef;
                        }
                }
                
                return null;
        }
*/
        /**
         * Returns all normalization rule defined
         * 
         * @return Map<Long, RuleDefinition> 
         * @throws Exception 
         */
        public Map<Long, RuleDefinition> getNormalizationRules() {
                return this.normalizationRuleDefinitions;
        }

        
        /**
         * True if feature has normalization rule defined
         * 
         * @param feature
         * @return boolean 
         * @throws Exception 
         */
        public boolean needsNormalization(long featureDefinitionID) 
                throws Exception {
                this.getFeatureDefinitions();
                
                FeatureDefinition featureDef = 
                        this.featureDefinitions.get(new Long(featureDefinitionID));
                
                if(featureDef.getNormalizationRuleDefinitionID() != 0L) {
                        return true;
                }
                
                return false;
        }
        
        /**
         * Returns normalization rule definition for rule definition ID
         * 
         * @param ruleID
         * @return RuleDefinition 
         * @throws Exception 
         */
        public RuleDefinition getNormalizationRuleDefinition(long ruleDefinitionID){
                return this.normalizationRuleDefinitions.get(new Long(ruleDefinitionID));
        }
        
        public HelpDocDefinition getHelpDocDefinition(long helpDocDefinitionID){
            return this.helpDocDefinitions.get(helpDocDefinitionID);
        }
}