# GovernanceArtifactImpl.java

    /*
     * Copyright (c) 2008 - 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.wso2.carbon.governance.api.common.dataobjects;

    import org.apache.axiom.om.OMElement;
    import org.apache.axiom.om.OMText;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.wso2.carbon.governance.api.common.util.ApproveItemBean;
    import org.wso2.carbon.governance.api.common.util.CheckListItemBean;
    import org.wso2.carbon.governance.api.exception.GovernanceException;
    import org.wso2.carbon.governance.api.util.CheckpointTimeUtils;
    import org.wso2.carbon.governance.api.util.GovernanceConstants;
    import org.wso2.carbon.governance.api.util.GovernanceUtils;
    import org.wso2.carbon.registry.core.Association;
    import org.wso2.carbon.registry.core.Registry;
    import org.wso2.carbon.registry.core.Resource;
    import org.wso2.carbon.registry.core.exceptions.RegistryException;
    import org.wso2.carbon.registry.core.session.UserRegistry;

    import javax.xml.namespace.QName;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;

    /**
     * Governance Artifact abstract class, This is overwritten by Endpoint, Policy, Schema, Service,
     * WSDL, People classes. This keeps common methods shared by all the governance artifacts
     */
    @SuppressWarnings("unused")
    public abstract class GovernanceArtifactImpl implements GovernanceArtifact {

        private static final Log log = LogFactory.getLog(GovernanceArtifactImpl.class);

        private String id;
        private String path;
        private Registry registry; // associated registry

        private String lcName;
        private String lcState;
        private String artifactPath;
        private List<String> uniqueAttributes;

        public List<String> getUniqueAttributes() {
            return uniqueAttributes;
        }

        public void setUniqueAttributes(List<String> uniqueAttributes) {
            this.uniqueAttributes = uniqueAttributes;
        }

        public String getLcName() {
            return lcName;
        }

        public void setLcName(String lcName) {
            this.lcName = lcName;
        }

        public String getLcState() {
            return lcState;
        }

        public void setLcState(String lcState) {
            this.lcState = lcState;
        }

        public String getArtifactPath() {
            return artifactPath;
        }

        public void setArtifactPath(String artifactPath) {
            this.artifactPath = artifactPath;
        }

        /**
         * Map of attributes associated with this governance artifact.
         */
        protected Map<String, List<String>> attributes = new HashMap<String, List<String>>();

        /**
         * Map of properties associated with this governance artifact.
         */
        protected Map<String, List<String>> properties = new HashMap<String, List<String>>();

        /**
         * Construct a governance artifact object from the path and the id.
         *
         * @param id the id
         */
        public GovernanceArtifactImpl(String id) {
            this.id = id;
        }

        /**
         * Construct a governance artifact. The default constructor.
         */
        public GovernanceArtifactImpl() {
            // the default constructor
        }

        /**
         * Copy constructor used for cloning.
         *
         * @param artifact the object to be copied.
         */
        protected GovernanceArtifactImpl(GovernanceArtifactImpl artifact) {
            if (artifact != null) {
                this.attributes = artifact.attributes;
                this.properties = artifact.properties;
                this.lcName = artifact.lcName;
                this.lcState = artifact.lcState;
                this.uniqueAttributes = artifact.uniqueAttributes;
    //            if (artifact.checkListItemBeans != null) {
    //                this.checkListItemBeans = Arrays.copyOf(artifact.checkListItemBeans, artifact.checkListItemBeans.length);
    //            }
    //            if (artifact.approveItemBeans != null) {
    //                this.approveItemBeans = Arrays.copyOf(artifact.approveItemBeans, artifact.approveItemBeans.length);
    //            }
                this.artifactPath = artifact.artifactPath;
                try {
                    associateRegistry(artifact.getAssociatedRegistry());
                } catch (GovernanceException ignored) {
                }
                setId(artifact.getId());
            }
        }

        protected GovernanceArtifactImpl(GovernanceArtifactImpl artifact,  List<String> uniqueAttributes) {
           this(artifact);
           setUniqueAttributes(uniqueAttributes);
        }

        /**
         * Constructor accepting resource identifier and the XML content.
         *
         * @param id             the resource identifier.
         * @param contentElement an XML element containing the content.
         * @throws GovernanceException if the construction fails.
         */
        public GovernanceArtifactImpl(String id, OMElement contentElement) throws GovernanceException {
            this(id);
            serializeToAttributes(contentElement, null);
        }

        public GovernanceArtifactImpl(String id, OMElement contentElement, List<String> uniqueAttributes) throws GovernanceException {
            this(id, contentElement);
            setUniqueAttributes(uniqueAttributes);
        }

        // Method to serialize attributes.
        private void serializeToAttributes(OMElement contentElement, String parentAttributeName)
                throws GovernanceException {
            Iterator childIt = contentElement.getChildren();
            if (childIt.hasNext()) {
            	while (childIt.hasNext()) {
                    Object childObj = childIt.next();
                    if (childObj instanceof OMElement) {
                        OMElement childElement = (OMElement) childObj;
                        String elementName = childElement.getLocalName();
                        String attributeName =
                                (parentAttributeName == null ? "" : parentAttributeName + "_") +
                                        elementName;
                        serializeToAttributes(childElement, attributeName);
                    } else if (childObj instanceof OMText) {
                        OMText childText = (OMText) childObj;
                        if (childText.getNextOMSibling() == null &&
                                childText.getPreviousOMSibling() == null) {
                            // if it is only child, we consider it is a value.
                            String textValue = childText.getText();
                            addAttribute(parentAttributeName, textValue);
                        }
                    }
                }
            } else {
            	if(!contentElement.getChildElements().hasNext()){
            		addAttribute(parentAttributeName, null);
            	}
            }

        }

        public static GovernanceArtifactImpl create(final Registry registry, final String artifactId)
                throws GovernanceException {
            return new GovernanceArtifactImpl(artifactId) {
                {
                    associateRegistry(registry);
                }

                public QName getQName() {
                    return null;
                }
                public void setQName(QName qName) throws GovernanceException {

                }
            };
        }

        public static GovernanceArtifactImpl create(final Registry registry, final String artifactId,
                                                    final OMElement content) throws GovernanceException {
            return new GovernanceArtifactImpl(artifactId, content) {
                {
                    associateRegistry(registry);
                }

                public QName getQName() {
                    return null;
                }
                public void setQName (QName qName)  throws GovernanceException {}
            };
        }

        public static GovernanceArtifactImpl create(final Registry registry, final String artifactId,
                                                    final List<String> uniqueAttributes)
                                                    throws GovernanceException {
            GovernanceArtifactImpl artifact = create(registry, artifactId);
            artifact.setUniqueAttributes(uniqueAttributes);
            return artifact;
        }

        public static GovernanceArtifactImpl create(final Registry registry, final String artifactId,
                                                    final OMElement content, List<String> uniqueAttributes)
                                                    throws GovernanceException {
            GovernanceArtifactImpl artifact = create(registry, artifactId, content);
            artifact.setUniqueAttributes(uniqueAttributes);
            return artifact;
        }

        /**
         * Returns the id of the artifact
         *
         * @return the id
         */
        @Override
        public String getId() {
            return id;
        }

        /**
         * Set the id
         *
         * @param id the id
         */
        @Override
        public void setId(String id) {
            this.id = id;
        }

        /**
         * Returns the path of the artifact, need to save the artifact before
         * getting the path.
         *
         * @return here we return the path of the artifact.
         * @throws GovernanceException if an error occurred.
         */
        @Override
        public String getPath() throws GovernanceException {
            if (path == null) {
                path = GovernanceUtils.getArtifactPath(registry, id);
            }
            return path;
        }

        public String getMediaType() {
            if(path == null) {
                try {
                    path = getPath();
                } catch (GovernanceException ex) {
                    log.error("An error occurred while obtaining the path of artifact " + ex);
                    return null;
                }
            }
            if(path != null) {
                try {
                    if (registry.resourceExists(path)) {
                        return registry.get(path).getMediaType();
                    }
                } catch(RegistryException ex) {
                    log.error("An error occurred obtaining the media type of the artifact " + ex);
                }
            }
            return null;
        }

        /**
         * Returns the name of the lifecycle associated with this artifact.
         *
         * @return the name of the lifecycle associated with this artifact.
         * @throws GovernanceException if an error occurred.
         */
        @Override
        public String getLifecycleName() throws GovernanceException {
            String path = getPath();
            if (path != null) {
                try {
                    if (!registry.resourceExists(path)) {
                        String msg =
                                "The artifact is not added to the registry. Please add the artifact " +
                                        "before reading lifecycle information.";
                        log.error(msg);
                        throw new GovernanceException(msg);
                    }
                    return registry.get(path).getProperty("registry.LC.name");
                } catch (RegistryException e) {
                    String msg = "Error in obtaining lifecycle name for the artifact. id: " + id +
                            ", path: " + path + ".";
                    log.error(msg, e);
                    throw new GovernanceException(msg, e);
                }
            }
            return null;
        }

        /**
         * Returns the name of the lifecycle associated with this artifact.
         *
         * @return the name of the lifecycle associated with this artifact.
         * @throws GovernanceException if an error occurred.
         */
        @Override
        public String[] getLifecycleNames() throws GovernanceException {
            String path = getPath();
            if (path != null) {
                try {
                    if (!registry.resourceExists(path)) {
                        String msg =
                                "The artifact is not added to the registry. Please add the artifact " +
                                        "before reading lifecycle information.";
                        log.error(msg);
                        throw new GovernanceException(msg);
                    }

                    List<String> lifeCycleNames = new ArrayList<String>();
                    Resource resource = registry.get(path);
                    for (Object object : resource.getProperties().keySet()) {
                        String property = (String) object;
                        if (property.startsWith("registry.LC.name.")) {
                            lifeCycleNames.add(resource.getProperty(property));
                        }
                    }

                    return lifeCycleNames.toArray(new String[lifeCycleNames.size()]);
                } catch (RegistryException e) {
                    String msg = "Error in obtaining lifecycle names for the artifact. id: " + id +
                            ", path: " + path + ".";
                    log.error(msg, e);
                    throw new GovernanceException(msg, e);
                }
            }
            return null;
        }

        /**
         * Associates the named lifecycle with the artifact
         *
         * @param name the name of the lifecycle to be associated with this artifact.
         * @throws GovernanceException if an error occurred.
         */
        @Override
        public void attachLifecycle(String name) throws GovernanceException {
            try {
                String path = getPath();
                if(name != null && path != null) {
                    registry.associateAspect(path, name);

                    Resource resource = registry.get(path);
                    if(resource.getAspects().size() == 1) {
                        // Since this is the first life-cycle we make it default
                        resource.setProperty("registry.LC.name", name);
                        registry.put(path, resource);
                    }
                }
            } catch (RegistryException e) {
                String msg = "Error in associating lifecycle for the artifact. id: " + id +
                        ", path: " + path + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * De-associate lifecycle associated with the artifact
         *
         * @throws GovernanceException if an error occurred.
         */
        public void detachLifecycle(String lifecycleName) throws GovernanceException {
            try {
                GovernanceUtils.removeAspect(path, lifecycleName, registry);
            } catch (RegistryException e) {
                String msg = "Error in de-associating lifecycle for the artifact. id: " + id +
                        ", path: " + path + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Returns the state of the lifecycle associated with this artifact.
         *
         * @return the state of the lifecycle associated with this artifact.
         * @throws GovernanceException if an error occurred.
         */
        @Override
        public String getLifecycleState() throws GovernanceException {
            String path = getPath();
            if (path != null) {
                try {
                    if (!registry.resourceExists(path)) {
                        String msg =
                                "The artifact is not added to the registry. Please add the artifact " +
                                        "before reading lifecycle information.";
                        log.error(msg);
                        throw new GovernanceException(msg);
                    }
                    Resource resource = registry.get(path);
                    for (Object object : resource.getProperties().keySet()) {
                        String property = (String) object;
                        if (property.startsWith("registry.lifecycle.") && property.endsWith(".state") && getLifecycleName() != null && property.contains((getLifecycleName()))) {
                            lcState = resource.getProperty(property);
                            return lcState;
                        }
                    }
                } catch (RegistryException e) {
                    String msg = "Error in obtaining lifecycle state for the artifact. id: " + id +
                            ", path: " + path + ".";
                    log.error(msg, e);
                    throw new GovernanceException(msg, e);
                }
            }
            return null;
        }

        /**
         * Returns the state of the lifecycle associated with this artifact.
         *
         * @return the state of the lifecycle associated with this artifact.
         * @throws GovernanceException if an error occurred.
         */
        @Override
        public String getLifecycleState(String lifeCycleName) throws GovernanceException {
            String path = getPath();
            if (path != null) {
                try {
                    if (!registry.resourceExists(path)) {
                        String msg =
                                "The artifact is not added to the registry. Please add the artifact " +
                                        "before reading lifecycle information.";
                        log.error(msg);
                        throw new GovernanceException(msg);
                    }
                    Resource resource = registry.get(path);
                    for (Object object : resource.getProperties().keySet()) {
                        String property = (String) object;
                        if (property.startsWith("registry.lifecycle.") && property.endsWith(".state") &&
                                property.substring(0,property.lastIndexOf(".")).endsWith(lifeCycleName)) {
                            return resource.getProperty(property);
                        }
                    }
                } catch (RegistryException e) {
                    String msg = "Error in obtaining lifecycle state for the artifact. id: " + id +
                            ", path: " + path + ".";
                    log.error(msg, e);
                    throw new GovernanceException(msg, e);
                }
            }
            return null;
        }

        /**
         * update the path after moving the resource.
         *
         * @throws GovernanceException if an error occurred.
         */
        public void updatePath() throws GovernanceException {
            path = GovernanceUtils.getArtifactPath(registry, id);
        }

        /**
         * update the path after moving the resource.
         *
         * @param artifactId id of the artifact
         * @throws GovernanceException if an error occurred.
         */
        public void updatePath(String artifactId) throws GovernanceException {
            path = GovernanceUtils.getArtifactPath(registry, artifactId);
        }

        /**
         * Create a version of the artifact.
         *
         * @throws GovernanceException throws if the operation failed.
         */
        public void createVersion() throws GovernanceException {
            checkRegistryResourceAssociation();
            try {
                if (!registry.resourceExists(path)) {
                    String msg =
                            "The artifact is not added to the registry. Please add the artifact " +
                                    "before creating versions.";
                    log.error(msg);
                    throw new GovernanceException(msg);
                }
                registry.createVersion(path);
            } catch (RegistryException e) {
                String msg = "Error in creating a version for the artifact. id: " + id +
                        ", path: " + path + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Associate a registry, this is mostly used by the artifact manager when creating the
         * artifact.
         *
         * @param registry the registry.
         * @throws GovernanceException throws if the operation failed.
         */
        public void associateRegistry(Registry registry) throws GovernanceException {
            this.registry = registry;
        }

        /**
         * Adding an attribute to the artifact. The artifact should be saved to get effect the change.
         * In the case of a single-valued attribute, this method will set or replace the existing
         * attribute with the provided value. In the case of a multi-valued attribute, this method will
         * append the provided value to the existing list.
         *
         * @param key   the key.
         * @param value the value.
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public void addAttribute(String key, String value) throws GovernanceException {
            boolean isAttribute = key.contains(".");
            if (!isAttribute) {
                List<String> values = attributes.get(key);
                if (values == null) {
                    values = new ArrayList<String>();
                    attributes.put(key, values);
                }
                values.add(value);
            } else {
                List<String> values = properties.get(key);
                if (values == null) {
                    values = new ArrayList<String>();
                    properties.put(key, values);
                }
                values.add(value);
            }
        }

        /**
         * Set/Update an attribute with multiple values. The artifact should be saved to get effect the
         * change.
         *
         * @param key       the key
         * @param newValues the value
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public void setAttributes(String key, String[] newValues) throws GovernanceException {
            boolean isAttribute = key.contains(".");
            if (!isAttribute) {
                List<String> values = new ArrayList<String>();
                values.addAll(Arrays.asList(newValues));
                attributes.put(key, values);
            } else {
                List<String> values = properties.get(key);
                if (values == null) {
                    values = new ArrayList<String>();
                    properties.put(key, values);
                }
                values.addAll(Arrays.asList(newValues));
            }

        }

        /**
         * Set/Update an attribute with a single value. The artifact should be saved to get effect the
         * change. This method will replace the existing attribute with the provided value. In the case
         * of a multi-valued attribute this will remove all existing values. If you want to append the
         * provided value to a list values of a multi-valued attribute, use the addAttribute method
         * instead.
         *
         * @param key      the key
         * @param newValue the value
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public void setAttribute(String key, String newValue) throws GovernanceException {
            boolean isAttribute = key.contains(".");
            if (!isAttribute) {
                List<String> values = new ArrayList<String>();
                values.add(newValue);
                attributes.put(key, values);
            } else {
                List<String> values = properties.get(key);
                if (values == null) {
                    values = new ArrayList<String>();
                    properties.put(key, values);
                }
                values.add(newValue);
            }

        }

        /**
         * Returns the attribute of a given key.
         *
         * @param key the key
         * @return the value of the attribute, if there are more than one attribute for the key this
         *         returns the first value.
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public String getAttribute(String key) throws GovernanceException {
            boolean isAttribute = key.contains(".");
            if (!isAttribute) {
                List<String> values = attributes.get(key);
                if (values == null || values.size() == 0) {
                    return null;
                }
                return values.get(0);
            } else {
                List<String> values = properties.get(key);
                if (values == null || values.size() == 0) {
                    return null;
                }
                return values.get(0);
            }

        }

        /**
         * Returns the available attribute keys
         *
         * @return an array of attribute keys.
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public String[] getAttributeKeys() throws GovernanceException {
            Set<String> attributeKeys = attributes.keySet();
            return attributeKeys.toArray(new String[attributeKeys.size()]);
        }

        /**
         * Returns the attribute values for a key.
         *
         * @param key the key.
         * @return attribute values for the key.
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public String[] getAttributes(String key) throws GovernanceException {
            boolean isAttribute = key.contains(".");
            if (!isAttribute) {
                List<String> values = attributes.get(key);
                if (values == null) {
                    return null; //TODO: This should return String[0]
                }
                return values.toArray(new String[values.size()]);
            } else {
                List<String> values = properties.get(key);
                if (values == null) {
                    return null; //TODO: This should return String[0]
                }
                return values.toArray(new String[values.size()]);
            }
        }

        /**
         * Remove attribute with the given key. The artifact should be saved to get effect the change.
         *
         * @param key the key
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public void removeAttribute(String key) throws GovernanceException {
            boolean isAttribute = key.contains(".");
            if (!isAttribute) {
                attributes.remove(key);
            } else {
                properties.remove(key);
            }

        }

        /**
         * Get dependencies of an artifacts. The artifacts should be saved, before calling this method.
         *
         * @return an array of dependencies of this artifact.
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public GovernanceArtifact[] getDependencies() throws GovernanceException {
            checkRegistryResourceAssociation();
            // uses the path from the getter to make sure the used overloaded method
            String path = getPath();
            List<GovernanceArtifact> governanceArtifacts = new ArrayList<GovernanceArtifact>();
            try {
                Association[] associations =
                        registry.getAssociations(path, GovernanceConstants.DEPENDS);
                for (Association association : associations) {
                    String destinationPath = association.getDestinationPath();
                    if (!destinationPath.equals(path)) {
                        GovernanceArtifact governanceArtifact =
                                GovernanceUtils.retrieveGovernanceArtifactByPath(registry, destinationPath);
                        //The Governance Artifact may not be returned if the user does not have permission to access it
                        if(governanceArtifact!=null){
                            governanceArtifacts.add(governanceArtifact);
                        }
                    }
                }
            } catch (RegistryException e) {
                String msg = "Error in getting dependencies from the artifact. id: " + id +
                        ", path: " + path + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
            return governanceArtifacts.toArray(new GovernanceArtifact[governanceArtifacts.size()]);
        }

        /**
         * Get dependents of an artifact. The artifacts should be saved, before calling this method.
         *
         * @return an array of artifacts that is dependent on this artifact.
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public GovernanceArtifact[] getDependents() throws GovernanceException {
            checkRegistryResourceAssociation();
            // uses the path from the getter to make sure the used overloaded method
            String path = getPath();
            List<GovernanceArtifact> governanceArtifacts = new ArrayList<GovernanceArtifact>();
            try {
                Association[] associations =
                        registry.getAssociations(path, GovernanceConstants.USED_BY);
                for (Association association : associations) {
                    String destinationPath = association.getDestinationPath();
                    if (!destinationPath.equals(path)) {
                        GovernanceArtifact governanceArtifact =
                                GovernanceUtils.retrieveGovernanceArtifactByPath(registry, destinationPath);
                        //The Governance Artifact may not be returned if the user does not have permission to access it
                        if(governanceArtifact!=null){
                            governanceArtifacts.add(governanceArtifact);
                        }
                    }
                }
            } catch (RegistryException e) {
                String msg = "Error in getting dependents from the artifact. id: " + id +
                        ", path: " + path + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
            return governanceArtifacts.toArray(new GovernanceArtifact[governanceArtifacts.size()]);
        }

        /**
         * Get all lifecycle actions for the current state of the lifecycle
         *
         * @param lifeCycleName lifecycle name of which actions are needed
         * @return Action set which can be invoked
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException
         *          throws if the operation failed.
         */
        public String[] getAllLifecycleActions(String lifeCycleName) throws GovernanceException {
        	String path = getPath();
            try {
                return registry.getAspectActions(path, lifeCycleName);
            } catch (RegistryException e) {
                String lifecycleState = getLifecycleState(lifeCycleName);
                String msg = "Error while retrieving the lifecycle actions " +
                        "for lifecycle: " + lifeCycleName + " in lifecycle state: " + lifecycleState;
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Invoke lifecycle action
         *
         * @param action lifecycle action tobe invoked
         * @param aspectName aspect name of which the action need to be invoked
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException
         *          throws if the operation failed.
         */
        public void invokeAction(String action, String aspectName) throws GovernanceException {
            invokeAction(action, new HashMap<String, String>(), aspectName);
        }

        /**
         * Invoke lifecycle action
         *
         * @param action     lifecycle action tobe invoked
         * @param parameters extra parameters needed when promoting
         * @param aspectName aspect name of which the action need to be invoked
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException
         *          throws if the operation failed.
         */
        public void invokeAction(String action, Map<String, String> parameters, String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            CheckListItemBean[] checkListItemBeans = GovernanceUtils.getAllCheckListItemBeans(artifactResource, this, aspectName);
            try {
                if (checkListItemBeans != null) {
                    for (CheckListItemBean checkListItemBean : checkListItemBeans) {
                        parameters.put(checkListItemBean.getOrder() + ".item", checkListItemBean.getValue().toString());
                    }
                }
                registry.invokeAspect(getArtifactPath(), aspectName, action, parameters);
            } catch (RegistryException e) {
                String msg = "Invoking lifecycle action \"" + action + "\" failed. " + e.getMessage();
                log.error(msg, e);
                throw new GovernanceException(e.getMessage(), e);
            }
        }

        /**
         * Retrieve name set of the checklist items
         *
         * @param aspectName lifecycle name of which action to be invoked
         * @return Checklist item name set
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException
         *          throws if the operation failed.
         */
        public String[] getAllCheckListItemNames(String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            CheckListItemBean[] checkListItemBeans = GovernanceUtils.getAllCheckListItemBeans(artifactResource, this, aspectName);
            if (checkListItemBeans == null) {
                return null;
            }
            String[] checkListItemNames = new String[checkListItemBeans.length];
            for (CheckListItemBean checkListItemBean : checkListItemBeans) {
                checkListItemNames[checkListItemBean.getOrder()] = checkListItemBean.getName();
            }
            return checkListItemNames;
        }

        /**
         * Check the checklist item
         *
         * @param aspectName lifecycle name of which action to be invoked
         * @param order order of the checklist item need to checked
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException
         *          throws if the operation failed.
         */
        public void checkLCItem(int order, String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            CheckListItemBean[] checkListItemBeans = GovernanceUtils.getAllCheckListItemBeans(artifactResource, this, aspectName);
            if (checkListItemBeans == null || order < 0 || order >= checkListItemBeans.length) {
                throw new GovernanceException("Invalid check list item.");
            } else if (checkListItemBeans[order].getValue()) {
                throw new GovernanceException("lifecycle checklist item \"" +
                        checkListItemBeans[order].getName() + "\" already checked");
            }
            try {
                setCheckListItemValue(order, true, checkListItemBeans, aspectName);
            } catch (RegistryException e) {
                String msg = "Checking LC item failed for check list item " + checkListItemBeans[order].getName();
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Check whether the given ordered lifecycle checklist item is checked or not
         *
         * @param order order of the checklist item need to unchecked
         * @param aspectName lifecycle name of which action to be invoked
         * @return whether the given ordered lifecycle checklist item is checked or not
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException
         *          throws if the operation failed.
         */
        public boolean isLCItemChecked(int order, String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            CheckListItemBean[] checkListItemBeans = GovernanceUtils.getAllCheckListItemBeans(artifactResource, this, aspectName);
            if (checkListItemBeans == null || order < 0 || order >= checkListItemBeans.length) {
                throw new GovernanceException("Invalid check list item.");
            }
            return checkListItemBeans[order].getValue();

        }

        /**
         * Un-check the checklist item
         *
         * @param order order of the checklist item need to unchecked
         * @param aspectName lifecycle name of which action to be invoked
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException
         *          throws if the operation failed.
         */
        public void uncheckLCItem(int order, String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            CheckListItemBean[] checkListItemBeans = GovernanceUtils.getAllCheckListItemBeans(artifactResource, this, aspectName);
            if (checkListItemBeans == null || order < 0 || order >= checkListItemBeans.length) {
                throw new GovernanceException("Invalid check list item.");
            } else if (!checkListItemBeans[order].getValue()) {
                throw new GovernanceException("lifecycle checklist item \"" +
                        checkListItemBeans[order].getName() + "\" not checked");
            }
            try {
                setCheckListItemValue(order, false, checkListItemBeans, aspectName);
            } catch (RegistryException e) {
                String msg = "Unchecking LC item failed for check list item: " + checkListItemBeans[order].getName();
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Set the checklist item value
         *
         * @param order order of the checklist item
         * @param value value of the checklist item
         * @param aspectName aspect name
         * @throws RegistryException throws if the operation failed.
         */
        private void setCheckListItemValue(int order, boolean value,
                                           CheckListItemBean[] checkListItemBeans, String aspectName) throws RegistryException {
            checkListItemBeans[order].setValue(value);
            Map<String, String> parameters = new HashMap<String, String>();
            for (CheckListItemBean checkListItemBean : checkListItemBeans) {
                parameters.put(checkListItemBean.getOrder() + ".item", checkListItemBean.getValue().toString());
            }
            registry.invokeAspect(getArtifactPath(), aspectName, "itemClick", parameters);
        }

        /**
         * Retrieve action set which need votes.
         *
         * @param aspectName Lifecycle name
         * @return Action set which can vote
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public String[] getAllVotingItems(String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            ApproveItemBean[] approveItemBeans = GovernanceUtils.
                    getAllApproveItemBeans(((UserRegistry) registry).getUserName(), artifactResource, this, aspectName);
            if (approveItemBeans == null) {
                throw new GovernanceException("No voting event found for the lifecycle: " + getLcName() +
                                                      " in lifecycle state: " + getLcState() + " of the artifact " +
                                                      getQName().getLocalPart());
            }
            String[] votingItems = new String[approveItemBeans.length];
            for (ApproveItemBean approveItemBean : approveItemBeans) {
                votingItems[approveItemBean.getOrder()] = approveItemBean.getName();
            }
            return votingItems;
        }

        /**
         * Retrieve action set which need votes.
         *
         * @return Action set which can vote
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public String[] getAllVotingItems() throws GovernanceException {
            return getAllVotingItems(getLifecycleName());
        }

        /**
         * Vote for an action.
         *
         * @param order      order of the action which need to be voted
         * @param aspectName Lifecycle name
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public void vote(int order, String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            ApproveItemBean[] approveItemBeans = GovernanceUtils.
                    getAllApproveItemBeans(((UserRegistry) registry).getUserName(), artifactResource, this, aspectName);
            if (approveItemBeans == null || order < 0 || order >= approveItemBeans.length) {
                throw new GovernanceException("Invalid voting action selected");
            } else if (approveItemBeans[order].getValue()) {
                throw new GovernanceException("Already voted for the action " + approveItemBeans[order].getName());
            }
            try {
                setVotingItemValue(order, true, approveItemBeans, aspectName);
            } catch (RegistryException e) {
                String msg = "Voting failed for action " + approveItemBeans[order].getName();
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Vote for an action.
         *
         * @param order order of the action which need to be voted
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public void vote(int order) throws GovernanceException {
            vote(order, getLifecycleName());
        }

        /**
         * Check whether the current user voted for given order event
         *
         * @param order      order of the action which need to be voted
         * @param aspectName Lifecycle name
         * @return whether the current user voted for the given order event
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public boolean isVoted(int order, String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            ApproveItemBean[] approveItemBeans = GovernanceUtils.
                    getAllApproveItemBeans(((UserRegistry) registry).getUserName(), artifactResource, this, aspectName);
            if (approveItemBeans == null || order < 0 || order >= approveItemBeans.length) {
                throw new GovernanceException("Invalid voting action selected");
            }
            return approveItemBeans[order].getValue();
        }

        /**
         * Check whether the current user voted for given order event.
         *
         * @param order order of the action which need to be voted
         * @return whether the current user voted for the given order event
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public boolean isVoted(int order) throws GovernanceException {
            return isVoted(order, getLifecycleName());
        }

        /**
         * Unvote for an action
         *
         * @param order      order of the action which need to be unvoted
         * @param aspectName Lifecycle name
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public void unvote(int order, String aspectName) throws GovernanceException {
            Resource artifactResource = getArtifactResource();
            ApproveItemBean[] approveItemBeans = GovernanceUtils.
                    getAllApproveItemBeans(((UserRegistry) registry).getUserName(), artifactResource, this, aspectName);
            if (approveItemBeans == null || order < 0 || order >= approveItemBeans.length) {
                throw new GovernanceException("Invalid voting action selected");
            } else if (!approveItemBeans[order].getValue()) {
                throw new GovernanceException("Not voted for the action \""
                                                      + approveItemBeans[order].getName() + "\"");
            }
            try {
                setVotingItemValue(order, false, approveItemBeans, aspectName);
            } catch (RegistryException e) {
                String msg = "Unvoting failed for action \"" + approveItemBeans[order].getName() + "\"";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Unvote for an action.
         *
         * @param order order of the action which need to be un voted
         * @throws org.wso2.carbon.governance.api.exception.GovernanceException throws if the operation failed.
         */
        public void unvote(int order) throws GovernanceException {
            unvote(order, getLifecycleName());
        }

        /**
         * Set the approval value
         *
         * @param order order of the approve event
         * @param value value of the approve
         * @throws RegistryException throws if the operation failed.
         */
        private void setVotingItemValue(int order, boolean value,
                                        ApproveItemBean[] approveItemBeans, String aspectName) throws RegistryException {
            approveItemBeans[order].setValue(value);
            Map<String, String> parameters = new HashMap<String, String>();
            for (ApproveItemBean approveItemBean : approveItemBeans) {
                parameters.put(approveItemBean.getOrder() + ".vote", approveItemBean.getValue().toString());
            }
            registry.invokeAspect(getArtifactPath(), aspectName, "voteClick", parameters);
        }

        /**
         * Attach the current artifact to an another artifact. Both the artifacts should be saved,
         * before calling this method. This method will two generic artifact types. There are specific
         * methods
         *
         * @param attachedToArtifact the artifact the current artifact is attached to
         * @throws GovernanceException throws if the operation failed.
         */
        public void attach(GovernanceArtifact attachedToArtifact) throws GovernanceException {
            checkRegistryResourceAssociation();
            // uses the path from the getter to make sure the used overloaded method
            String path = getPath();
            String attachedToArtifactPath = attachedToArtifact.getPath();
            if (attachedToArtifactPath == null) {
                String msg = "'Attached to artifact' is not associated with a registry path.";
                log.error(msg);
                throw new GovernanceException(msg);
            }
            try {
                registry.addAssociation(attachedToArtifactPath, path, GovernanceConstants.USED_BY);
                registry.addAssociation(path, attachedToArtifactPath, GovernanceConstants.DEPENDS);
            } catch (RegistryException e) {
                String msg = "Error in attaching the artifact. source id: " + id + ", path: " + path +
                        ", target id: " + attachedToArtifact.getId() + ", path:" +
                        attachedToArtifactPath +
                        ", attachment type: " + attachedToArtifact.getClass().getName() + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Detach the current artifact from the provided artifact. Both the artifacts should be saved,
         * before calling this method.
         *
         * @param artifactId the artifact id of the attached artifact
         * @throws GovernanceException throws if the operation failed.
         */
        public void detach(String artifactId) throws GovernanceException {
            checkRegistryResourceAssociation();
            // uses the path from the getter to make sure the used overloaded method
            String path = getPath();
            String artifactPath = GovernanceUtils.getArtifactPath(registry, artifactId);
            if (artifactPath == null) {
                String msg = "Attached to artifact is not associated with a registry path.";
                log.error(msg);
                throw new GovernanceException(msg);
            }
            try {
                registry.removeAssociation(path, artifactPath, GovernanceConstants.DEPENDS);
                registry.removeAssociation(artifactPath, path, GovernanceConstants.USED_BY);
            } catch (RegistryException e) {
                String msg = "Error in detaching the artifact. source id: " + id + ", path: " + path +
                        ", target id: " + artifactId +
                        ", target path:" + artifactPath + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Validate the resource is associated with a registry
         *
         * @throws GovernanceException if the resource is not associated with a registry.
         */
        protected void checkRegistryResourceAssociation() throws GovernanceException {
            // uses the path from the getter to make sure the used overloaded method
            String path = getPath();
            if (registry == null) {
                String msg = "A registry is not associated with the artifact.";
                log.error(msg);
                throw new GovernanceException(msg);
            }
            if (path == null) {
                String msg = "A path is not associated with the artifact.";
                log.error(msg);
                throw new GovernanceException(msg);
            }
            if (id == null) {
                String msg = "An id is not associated with the artifact.";
                log.error(msg);
                throw new GovernanceException(msg);
            }
        }

        /**
         * Returns the associated registry to the artifact.
         *
         * @return the associated registry
         */
        protected Registry getAssociatedRegistry() {
            return registry;
        }

        /**
         * Get the resource related to this artifact
         *
         * @return resource related to this artifact
         * @throws GovernanceException if there is no resource related to the artifact in the registry
         */
        private Resource getArtifactResource() throws GovernanceException {
            Resource artifactResource;
            try {
                return registry.get(artifactPath);
            } catch (RegistryException e) {
                String msg = "Artifact resource \"" + getQName().getLocalPart() + "\" not found in the registry";
                throw new GovernanceException();
            }
        }

        /**
         * Returns the available attribute keys
         *
         * @return an array of attribute keys.
         * @throws GovernanceException throws if the operation failed.
         */
        @Override
        public String[] getPropertyKeys() throws GovernanceException {
            Set<String> attributeKeys = properties.keySet();
            return attributeKeys.toArray(new String[attributeKeys.size()]);
        }

        @Override
        public boolean equals(Object artifact) {
            GovernanceArtifact governanceArtifact ;
            if(!(artifact instanceof GovernanceArtifact)) {
                return false;
            } else {
                governanceArtifact = (GovernanceArtifact) artifact;
            }

            return governanceArtifact.getId().equals(this.getId());
        }

        @Override
        public void attach(String artifactId) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public void addAssociation(String associationType, GovernanceArtifact attachedToArtifact)
                throws GovernanceException {
            checkRegistryResourceAssociation();
            // uses the path from the getter to make sure the used overloaded method
            String path = getPath();
            String attachedToArtifactPath = attachedToArtifact.getPath();
            if (attachedToArtifactPath == null) {
                String msg = "'Attached to artifact' is not associated with a registry path.";
                log.error(msg);
                throw new GovernanceException(msg);
            }
            try {
                registry.addAssociation(path, attachedToArtifactPath, associationType);
            } catch (RegistryException e) {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append("Error in attaching the artifact. source id: ")
                        .append(id)
                        .append(", path: ")
                        .append(path)
                        .append(", target id: ")
                        .append(attachedToArtifact.getId())
                        .append(", path:")
                        .append(attachedToArtifactPath)
                        .append(", attachment type: ")
                        .append(attachedToArtifact.getClass().getName());
                throw new GovernanceException(stringBuilder.toString(), e);
            }    }

        @Override
        public void addAssociation(String associationType, String artifactId) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public void addBidirectionalAssociation(String forwardType, String backwardType,
                                                GovernanceArtifact attachedToArtifact) throws GovernanceException {
            checkRegistryResourceAssociation();
            // uses the path from the getter to make sure the used overloaded method
            String path = getPath();
            String attachedToArtifactPath = attachedToArtifact.getPath();
            if (attachedToArtifactPath == null) {
                String msg = "'Attached to artifact' is not associated with a registry path.";
                log.error(msg);
                throw new GovernanceException(msg);
            }
            try {
                registry.addAssociation(path, attachedToArtifactPath, forwardType);
                registry.addAssociation(attachedToArtifactPath, path, backwardType);
            } catch (RegistryException e) {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append("Error in attaching the artifact. source id: ")
                        .append(id)
                        .append(", path: ")
                        .append(path)
                        .append(", target id: ")
                        .append(attachedToArtifact.getId())
                        .append(", path:")
                        .append(attachedToArtifactPath)
                        .append(", attachment type: ")
                        .append(attachedToArtifact.getClass().getName());
                throw new GovernanceException(stringBuilder.toString(), e);
            }
        }

        @Override
        public void removeAssociation(String associationType, String artifactId) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public void removeAssociation(String artifactId) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public Map<String, List<GovernanceArtifact>> getAssociations() throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public Map<String, List<String>> getAssociatedArtifactIds() throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public boolean isRegistryAwareArtifact() {
            try {
                checkRegistryResourceAssociation();
                return true;
            } catch (GovernanceException e) {
                return false;
            }
        }

        @Override
        public void addTag(String tag) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public void addTags(List<String> tags) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public List<String> listTags() throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public void removeTag(String tag) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public void removeTags(List<String> tags) throws GovernanceException {
            throw new UnsupportedOperationException("Not yet Implemented");
        }

        @Override
        public String toString() {
            return "GovernanceArtifactImpl{" +
                   "attributes=" + attributes +
                   ", id='" + id + '\'' +
                   '}';
        }

        public boolean uniqueTo(GovernanceArtifact artifact) {
            if (artifact != null) {
                List<String> uAttributes = getUniqueAttributes(artifact);
                if (this == artifact || this.equals(artifact)) {
                    return true;
                } else if (uAttributes != null && uAttributes.size() > 0) {
                    try {
                        for (String attributeName : uAttributes) {
                            if (this.getAttribute(attributeName) != null && artifact.getAttribute(attributeName) !=
                                                                            null && !this.getAttribute(attributeName).equals
                                    (artifact.getAttribute(attributeName))) {
                                return false;
                            }
                        }
                        //all unique attributes are same
                        return true;
                    } catch (GovernanceException e) {
                        log.error(e);
                    }
                }
            }
            return false;
        }

        private List<String> getUniqueAttributes(GovernanceArtifact artifact) {
            if(this.uniqueAttributes != null){
                return uniqueAttributes;
            } else if(artifact instanceof GovernanceArtifactImpl){
                return ((GovernanceArtifactImpl)artifact).getUniqueAttributes();
            }
            return null;
        }

        public boolean compareTo(GovernanceArtifact artifact) {
            if (artifact != null) {
                if (this == artifact || this.equals(artifact)) {
                    return true;
                } else {
                    try {
                        for (String key : this.getAttributeKeys()) {
                            if (!this.getAttribute(key).equals(artifact.getAttribute(key))) {
                                return false;
                            }
                        }
                        //all unique attributes are same
                        return true;
                    } catch (GovernanceException e) {
                        log.error(e);
                    }
                }
            }
            return false;
        }

        /**
         * TODO :Move this implementation to a solr based implementation in C5.
         */
        /**
         * This method is used to get a lifecycle's current state duration information.
         *
         * @param artifactID lifecycle associated artifacts id.
         * @param lcName     lifecycle name.
         * @return a map of current lifecycle state duration colour and duration.
         * @throws GovernanceException
         */
        @Override
        public Map<String, String> getCurrentStateDuration(String artifactID, String lcName) throws GovernanceException {

            if (artifactPath == null || lcName == null) {
                return null;
            }

            String durationColour = null;
            String currentStateDuration = null;
            String lifecycleName;
            Map<String, String> currentLCStateDurationInfo = new HashMap<>();

            if (lcName.isEmpty()) {
                lcName = getLifecycleName();
            }
            String artifactPath = GovernanceUtils.getArtifactPath(registry, artifactID);
            try {
                if (registry.resourceExists(artifactPath)) {
                    Resource resource = registry.get(artifactPath);
                    List<String> checkpoints = resource.getPropertyValues(GovernanceConstants.REGISTRY_LIFECYCLE + lcName
                            + GovernanceConstants.CHECKPOINT);

                    if (checkpoints != null) {

                        for (String checkpoint : checkpoints) {
                            List<String> checkpointValues = resource
                                    .getPropertyValues(GovernanceConstants.REGISTRY_LIFECYCLE + lcName +
                                            GovernanceConstants.CHECKPOINT + GovernanceConstants.DOT + checkpoint);
                            if (checkpointValues != null) {
                                String checkpointName = checkpointValues.get(0);
                                String checkpointMin = checkpointValues.get(1);
                                String checkpointMax = checkpointValues.get(2);
                                String checkpointLastUpdatedTime = checkpointValues.get(3);
                                String checkpointColour = checkpointValues.get(4);

                                long duration = CheckpointTimeUtils.calculateTimeDifference(CheckpointTimeUtils
                                        .getCurrentTime(), checkpointLastUpdatedTime);
                                if (CheckpointTimeUtils.isDurationBetweenTimestamps(duration, checkpointMin,
                                        checkpointMax)) {
                                    currentLCStateDurationInfo
                                            .put(GovernanceConstants.LIFECYCLE_DURATION_COLOUR, checkpointColour);
                                    currentLCStateDurationInfo
                                            .put(GovernanceConstants.LIFECYCLE_DURATION, CheckpointTimeUtils
                                                    .formatTimeDuration(duration));
                                    break;
                                }
                            }
                        }
                    } else {
                        String lastUpdateTIme = resource.getProperty(GovernanceConstants.REGISTRY_LIFECYCLE + lcName +
                                GovernanceConstants.LAST_UPDATED_TIME);
                        if (lastUpdateTIme != null) {
                            long duration = CheckpointTimeUtils.calculateTimeDifferenceToPresent(lastUpdateTIme);
                            currentLCStateDurationInfo.put(GovernanceConstants.LIFECYCLE_DURATION_COLOUR, null);
                            currentLCStateDurationInfo
                                    .put(GovernanceConstants.LIFECYCLE_DURATION,
                                            CheckpointTimeUtils.formatTimeDuration(duration));
                        } else {
                            return null;
                        }
                    }

                    if (currentLCStateDurationInfo.isEmpty()) {
                        String lastUpdateTIme = resource.getProperty(GovernanceConstants.REGISTRY_LIFECYCLE + lcName +
                                GovernanceConstants.LAST_UPDATED_TIME);
                        if (lastUpdateTIme != null) {
                            long duration = CheckpointTimeUtils.calculateTimeDifferenceToPresent(lastUpdateTIme);
                            currentLCStateDurationInfo.put(GovernanceConstants.LIFECYCLE_DURATION_COLOUR, null);
                            currentLCStateDurationInfo
                                    .put(GovernanceConstants.LIFECYCLE_DURATION,
                                            CheckpointTimeUtils.formatTimeDuration(duration));
                        } else {
                            return null;
                        }
                    }
                }
            } catch (RegistryException e) {
                throw new GovernanceException("Error occurred while getting current lifecycle state duration info. ", e);
            }

            return currentLCStateDurationInfo;
        }

    }