# GovernanceUtils.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.util;

    import org.apache.axiom.om.OMElement;
    import org.apache.axiom.om.impl.builder.StAXOMBuilder;
    import org.apache.axiom.om.util.AXIOMUtil;
    import org.apache.axiom.om.xpath.AXIOMXPath;
    import org.apache.commons.lang.StringUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.jaxen.JaxenException;
    import org.wso2.carbon.base.CarbonContextHolderBase;
    import org.wso2.carbon.base.UnloadTenantTask;
    import org.wso2.carbon.context.CarbonContext;
    import org.wso2.carbon.context.PrivilegedCarbonContext;
    import org.wso2.carbon.governance.api.cache.*;
    import org.wso2.carbon.governance.api.common.dataobjects.GovernanceArtifact;
    import org.wso2.carbon.governance.api.common.dataobjects.GovernanceArtifactImpl;
    import org.wso2.carbon.governance.api.common.util.ApproveItemBean;
    import org.wso2.carbon.governance.api.common.util.CheckListItemBean;
    import org.wso2.carbon.governance.api.endpoints.dataobjects.Endpoint;
    import org.wso2.carbon.governance.api.endpoints.dataobjects.EndpointImpl;
    import org.wso2.carbon.governance.api.exception.GovernanceException;
    import org.wso2.carbon.governance.api.generic.dataobjects.GenericArtifactImpl;
    import org.wso2.carbon.governance.api.policies.dataobjects.Policy;
    import org.wso2.carbon.governance.api.policies.dataobjects.PolicyImpl;
    import org.wso2.carbon.governance.api.schema.dataobjects.Schema;
    import org.wso2.carbon.governance.api.schema.dataobjects.SchemaImpl;
    import org.wso2.carbon.governance.api.wsdls.dataobjects.Wsdl;
    import org.wso2.carbon.governance.api.wsdls.dataobjects.WsdlImpl;
    import org.wso2.carbon.registry.common.AttributeSearchService;
    import org.wso2.carbon.registry.common.ResourceData;
    import org.wso2.carbon.registry.common.TermData;
    import org.wso2.carbon.registry.core.Association;
    import org.wso2.carbon.registry.core.Registry;
    import org.wso2.carbon.registry.core.RegistryConstants;
    import org.wso2.carbon.registry.core.Resource;
    import org.wso2.carbon.registry.core.config.RegistryContext;
    import org.wso2.carbon.registry.core.exceptions.RegistryException;
    import org.wso2.carbon.registry.core.jdbc.handlers.RequestContext;
    import org.wso2.carbon.registry.core.pagination.PaginationContext;
    import org.wso2.carbon.registry.core.secure.AuthorizationFailedException;
    import org.wso2.carbon.registry.core.service.RegistryService;
    import org.wso2.carbon.registry.core.session.UserRegistry;
    import org.wso2.carbon.registry.core.utils.MediaTypesUtils;
    import org.wso2.carbon.registry.core.utils.RegistryUtils;
    import org.wso2.carbon.registry.core.utils.UUIDGenerator;
    import org.wso2.carbon.registry.extensions.utils.CommonUtil;
    import org.wso2.carbon.registry.indexing.IndexingConstants;
    import org.wso2.carbon.registry.indexing.service.ContentSearchService;
    import org.wso2.carbon.registry.indexing.service.TermsQuerySearchService;
    import org.wso2.carbon.registry.indexing.service.TermsSearchService;
    import org.wso2.carbon.utils.component.xml.config.ManagementPermission;
    import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
    import org.wso2.carbon.utils.multitenancy.MultitenantUtils;

    import javax.cache.Cache;
    import javax.cache.CacheManager;
    import javax.cache.Caching;
    import javax.xml.namespace.QName;
    import javax.xml.stream.XMLInputFactory;
    import javax.xml.stream.XMLStreamException;
    import javax.xml.stream.XMLStreamReader;
    import java.io.StringReader;
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    import java.util.Set;
    import java.util.TreeSet;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    /**
     * Utilities used by various Governance API related functionality.
     */
    public class GovernanceUtils {

        private static final Log log = LogFactory.getLog(GovernanceUtils.class);
        private static final String OVERVIEW = "overview";
        private static final String UNDERSCORE = "_";
        private static final String FIELDS_OR_WILD_SEARCH = " or*&";
        private static final String FIELDS_OR_SEARCH = " or&";
        private static final String FIELDS_AND_WILD_SEARCH = " and*&";
        private static final String SYMBOL_EQUAL = "=";
        private static final String SYMBOL_COLON = ":";
        private static final String FIELDS_AND_SEARCH = " and&";
        private static final String SYMBOL_AND = "&";
        private static final String REPLACEMENT_OR_WILD_SEARCH = "* OR ";
        private static final String REPLACEMENT_AND_WILD_SEARCH = "* AND ";
        private static final String REPLACEMENT_OR_SEARCH = " OR ";
        private static final String REPLACEMENT_AND_SEARCH = "AND ";
        private static final String REPLACEMENT_SYMBOL_AND = " AND ";
        private static RegistryService registryService;
        //private static final String SEPARATOR = ":";
        private final static Map<Integer, List<GovernanceArtifactConfiguration>>
                artifactConfigurations = new HashMap<Integer, List<GovernanceArtifactConfiguration>>();
        private static Map<Integer, Map<String, Boolean>> lifecycleAspects =
                new HashMap<Integer, Map<String, Boolean>>();

        private static final Object ASPECT_MAP_LOCK = new Object();

        private static AttributeSearchService attributeSearchService;

        private static final ThreadLocal<Registry> tenantGovernanceSystemRegistry = new ThreadLocal<Registry>();
        private final static RXTConfigCacheEntryCreatedListener<String, Boolean> entryCreatedListener = new RXTConfigCacheEntryCreatedListener<String, Boolean>();
        private final static RXTConfigCacheEntryRemovedListener<String, Boolean> entryRemovedListener = new RXTConfigCacheEntryRemovedListener<String, Boolean>();
        private final static RXTConfigCacheEntryUpdatedListener<String, Boolean> entryUpdatedListener = new RXTConfigCacheEntryUpdatedListener<String, Boolean>();
        private static boolean rxtCacheInitiated = false;

        private static TermsSearchService termsSearchService;

        private static ContentSearchService contentSearchService;

        private static TermsQuerySearchService termsQuerySearchService;
        /**
         * Setting the registry service.
         *
         * @param registryService the registryService.
         */
        public static void setRegistryService(RegistryService registryService) {
            GovernanceUtils.registryService = registryService;
        }

        // Method to register a list of governance artifact configurations.
        private static void registerArtifactConfigurations(int tenantId,
                                                           List<GovernanceArtifactConfiguration> configurations) {
            artifactConfigurations.put(tenantId, configurations);
            CarbonContextHolderBase.registerUnloadTenantTask(new UnloadTenantTask() {
                public void register(int tenantId, Object registration) {
                    // Nothing to register in here.
                }

                public void cleanup(int tenantId) {
                    if (artifactConfigurations.get(tenantId) != null) {
                        artifactConfigurations.remove(tenantId);
                    }
                    if (lifecycleAspects.get(tenantId) != null) {
                        lifecycleAspects.remove(tenantId);
                    }
                }
            });
        }

        /**
         * This method is used to add artifact configurations into the artifact configuration map given the registry path
         *
         * @param registry registry instance
         * @param tenantId tenant id
         * @param path path of the resource
         * @throws RegistryException
         */
        public static void registerArtifactConfigurationByPath(Registry registry, int tenantId, String path) throws RegistryException {

            GovernanceArtifactConfiguration governanceArtifactConfiguration;
            Resource resource = registry.get(path);
            Object content = resource.getContent();
            String elementString;
            if (content instanceof String) {
                elementString = (String) content;
            } else {
                elementString = RegistryUtils.decodeBytes((byte[]) content);
            }
            governanceArtifactConfiguration = getGovernanceArtifactConfiguration(elementString);
            List<GovernanceArtifactConfiguration> configurations = artifactConfigurations.get(tenantId);

            if (configurations != null) {
                configurations.add(governanceArtifactConfiguration);
            } else {
                configurations = new LinkedList<GovernanceArtifactConfiguration>();
                configurations.add(governanceArtifactConfiguration);
            }
            artifactConfigurations.put(tenantId, configurations);

        }

       /**
         * Query to search for governance artifacts.
         *
         * @param mediaType the media type of the artifacts to be searched for.
         * @param registry  the registry instance to run query on.
         * @return the list of artifact paths.
         * @throws RegistryException if the operation failed.
         */
        public static String[] findGovernanceArtifacts(String mediaType, Registry registry)
                throws RegistryException {
            String[] paths = MediaTypesUtils.getResultPaths(registry, mediaType);
            if (paths == null) {
                paths = new String[0];
            }
            Arrays.sort(paths, new Comparator<String>() {

                public int compare(String o1, String o2) {
                    int result = RegistryUtils.getResourceName(o1).compareToIgnoreCase(RegistryUtils.getResourceName(o2));
                    if (result == 0) {
                        return o1.compareToIgnoreCase(o2);
                    }
                    return result;
                }
            });
            return paths;
        }

        /**
         * Query to search for a governance artifact configuration.
         *
         * @param mediaType the media type of the artifact configuration.
         * @param registry  the registry instance to run query on.
         * @return the artifact configuration.
         * @throws RegistryException if the operation failed.
         */
        public static GovernanceArtifactConfiguration findGovernanceArtifactConfigurationByMediaType(
                String mediaType, Registry registry)
                throws RegistryException {

            List<GovernanceArtifactConfiguration> governanceArtifactConfigurations = artifactConfigurations.get(((UserRegistry) registry).getTenantId());

            if (governanceArtifactConfigurations == null || governanceArtifactConfigurations.isEmpty()) {
                governanceArtifactConfigurations = findGovernanceArtifactConfigurations(registry);
                artifactConfigurations.put(((UserRegistry) registry).getTenantId(), governanceArtifactConfigurations);
            }
            for (GovernanceArtifactConfiguration configuration : governanceArtifactConfigurations) {
                if (mediaType.equals(configuration.getMediaType())) {
                    return configuration;
                }
            }
            return null;
        }

        /**
         * Query to search for a governance artifact configuration.
         *
         * @param key      the key of the artifact configuration.
         * @param registry the registry instance to run query on.
         * @return the artifact configuration.
         * @throws RegistryException if the operation failed.
         */
        public static GovernanceArtifactConfiguration findGovernanceArtifactConfiguration(
                String key, Registry registry)
                throws RegistryException {

            List<GovernanceArtifactConfiguration> governanceArtifactConfigurations = artifactConfigurations.get(((UserRegistry) registry).getTenantId());

            if (governanceArtifactConfigurations == null || governanceArtifactConfigurations.isEmpty()) {
                governanceArtifactConfigurations = findGovernanceArtifactConfigurations(registry);
                artifactConfigurations.put(((UserRegistry) registry).getTenantId(), governanceArtifactConfigurations);
            }
            for (GovernanceArtifactConfiguration configuration : governanceArtifactConfigurations) {
                if (key.equals(configuration.getKey())) {
                    return configuration;
                }
            }
            return null;
        }

        /**
         *
         * @param key short name of the artifact type.
         * @param contextName context name of which lifecycle is needed
         * @param registry registry instance
         * @return lifecycle of the name associated with the context, null otherwise
         * @throws RegistryException if the operation failed
         */
        public static String getLifeCycleOfContext(String key, String contextName, Registry registry) throws RegistryException {
            GovernanceArtifactConfiguration configuration = findGovernanceArtifactConfiguration(key, registry);

            if(configuration != null) {
                return configuration.getLifeCycleOfContext(contextName);
            }

            return null ;
        }

        /**
         * Method to obtain a list of paths having resources of the given media type.
         *
         * @param registry  the registry instance to run query on.
         * @param mediaType the media type.
         * @return an array of resource paths.
         * @throws GovernanceException if the operation failed.
         */
        public static String[] getResultPaths(Registry registry, String mediaType) throws GovernanceException {
            try {
                return MediaTypesUtils.getResultPaths(registry, mediaType);
            } catch (RegistryException e) {
                String msg = "Error in getting the result for media type: " + mediaType + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        // remove symbolic links in search items.
        @SuppressWarnings("unused")
        private static String[] removeSymbolicLinks(String[] paths, Registry governanceRegistry) {
            if (paths == null) {
                return new String[0];
            }
            List<String> fixedPaths = new LinkedList<String>();
            for (String path : paths) {
                try {
                    if ((governanceRegistry.get(path).getProperty(RegistryConstants.REGISTRY_LINK) ==
                            null || governanceRegistry.get(path).getProperty(
                            RegistryConstants.REGISTRY_REAL_PATH) != null) &&
                            !path.contains(RegistryConstants.SYSTEM_MOUNT_PATH)) {
                        fixedPaths.add(path);
                    }
                } catch (RegistryException ignored) {
                }
            }
            return fixedPaths.toArray(new String[fixedPaths.size()]);
        }

        /**
         * Method to load the Governance Artifacts to be used by the API operations.
         *
         * @param registry       the registry instance used to search for artifacts.
         * @param configurations the artifact configurations to load.
         * @throws RegistryException if the operation failed.
         */
        public static void loadGovernanceArtifacts(UserRegistry registry,
                                                   List<GovernanceArtifactConfiguration> configurations)
                throws RegistryException {
            registerArtifactConfigurations(registry.getTenantId(), configurations);
        }

        /**
         * Method to load the Governance Artifacts to be used by the API operations.
         *
         * @param registry the registry instance used to search for artifacts.
         * @throws RegistryException if the operation failed.
         */
        public static void loadGovernanceArtifacts(UserRegistry registry) throws RegistryException {
            if (!artifactConfigurations.containsKey(registry.getTenantId())) {
                loadGovernanceArtifacts(registry, Collections
                        .unmodifiableList(findGovernanceArtifactConfigurations(registry)));
            }
        }

        public static GovernanceArtifactConfiguration getGovernanceArtifactConfiguration(String elementString) {
            GovernanceArtifactConfiguration configuration = null;
            try {
                OMElement configElement = AXIOMUtil.stringToOM(elementString);
                if (configElement != null) {
                    configuration = new GovernanceArtifactConfiguration();
                    OMElement artifactNameAttributeElement = configElement.getFirstChildWithName(
                            new QName("nameAttribute"));
                    if (artifactNameAttributeElement != null) {
                        configuration.setArtifactNameAttribute(
                                artifactNameAttributeElement.getText());
                    }
                    OMElement artifactNamespaceAttributeElement =
                            configElement.getFirstChildWithName(
                                    new QName("namespaceAttribute"));
                    if (artifactNamespaceAttributeElement != null) {
                        configuration.setArtifactNamespaceAttribute(
                                artifactNamespaceAttributeElement.getText());
                    } else if (Boolean.toString(false).equals(
                            configElement.getAttributeValue(new QName("hasNamespace")))) {
                        configuration.setArtifactNamespaceAttribute(null);
                    } else {
                        configuration.setHasNamespace(true);
                    }
                    OMElement artifactElementRootElement = configElement.getFirstChildWithName(
                            new QName("elementRoot"));
                    if (artifactElementRootElement != null) {
                        configuration.setArtifactElementRoot(
                                artifactElementRootElement.getText());
                    }
                    OMElement artifactElementNamespaceElement = configElement.getFirstChildWithName(
                            new QName("elementNamespace"));
                    if (artifactElementNamespaceElement != null) {
                        configuration.setArtifactElementNamespace(
                                artifactElementNamespaceElement.getText());
                    }
                    configuration.setKey(configElement.getAttributeValue(new QName("shortName")));
                    configuration.setSingularLabel(
                            configElement.getAttributeValue(new QName("singularLabel")));
                    configuration.setPluralLabel(
                            configElement.getAttributeValue(new QName("pluralLabel")));
                    configuration.setMediaType(
                            configElement.getAttributeValue(new QName("type")));
                    configuration.setExtension(
                            configElement.getAttributeValue(new QName("fileExtension")));

                    String iconSetString = configElement.getAttributeValue(new QName("iconSet"));
                    if (iconSetString != null) {
                        configuration.setIconSet(Integer.parseInt(iconSetString));
                    }

                    OMElement pathExpressionElement = configElement.getFirstChildWithName(
                            new QName("storagePath"));
                    if (pathExpressionElement != null) {
                        configuration.setPathExpression(pathExpressionElement.getText());
                    } else {
                        configuration.setPathExpression("/@{name}");
                    }

                    OMElement lifecycleElement = configElement.getFirstChildWithName(
                            new QName("lifecycle"));
                    if (lifecycleElement != null) {
                        configuration.setLifecycle(lifecycleElement.getText());
                    }

                    OMElement taxonomiesElement = configElement.getFirstChildWithName(new QName("taxonomies"));
                    if (taxonomiesElement != null) {
                        Iterator taxonomiesElements = taxonomiesElement.getChildrenWithName(new QName("taxonomy"));
                        String isGlobalTaxonomyEnabled = taxonomiesElement.getAttributeValue(new QName("excludeGlobal"));

                        while (taxonomiesElements.hasNext()) {
                            OMElement taxonomyElement = (OMElement) taxonomiesElements.next();
                            if (taxonomyElement != null) {
                                String name = taxonomyElement.getAttributeValue(new QName("name"));
                                String isDisable = taxonomyElement.getAttributeValue(new QName("disable"));
                                configuration.setTaxonomy(name, Boolean.valueOf(isDisable),
                                        Boolean.valueOf(isGlobalTaxonomyEnabled));
                            }
                        }
                    }

                    OMElement groupingAttributeElement = configElement.getFirstChildWithName(
                            new QName("groupingAttribute"));
                    if (groupingAttributeElement != null) {
                        configuration.setGroupingAttribute(groupingAttributeElement.getText());
                    }

                    OMElement lifecycleContextsElement = configElement.getFirstChildWithName(new QName("lifecycleContexts"));
                    if(lifecycleContextsElement != null) {
                        Iterator lifecycleContextsIterator = lifecycleContextsElement.getChildrenWithName(new QName("lifecycleContext"));

                        while(lifecycleContextsIterator.hasNext()) {
                            OMElement lifecycleContextElement = (OMElement) lifecycleContextsIterator.next();
                            String lcName = lifecycleContextElement.getAttributeValue(new QName("lcName"));
                            String contextsStr = lifecycleContextElement.getText();

                            String[] contexts = contextsStr.split(",");
                            for(String context : contexts) {
                                configuration.addLifeCycleToContext(context, lcName);
                            }
                        }
                    }

                    OMElement contentDefinition = configElement.getFirstChildWithName(
                            new QName("content"));
                    if (contentDefinition != null) {
                        String href = contentDefinition.getAttributeValue(new QName("href"));
                        if (href != null) {
                            configuration.setContentURL(href);
                        }
                        configuration.setContentDefinition(contentDefinition);
                    }
                    OMElement associationDefinitions = configElement.getFirstChildWithName(
                            new QName("relationships"));
                    if (associationDefinitions != null) {
                        List<Association> associations =
                                new LinkedList<Association>();
                        Iterator associationElements =
                                associationDefinitions.getChildrenWithName(
                                        new QName("association"));
                        while (associationElements.hasNext()) {
                            OMElement associationElement = (OMElement) associationElements.next();
                            String type = associationElement.getAttributeValue(new QName("type"));
                            String source =
                                    associationElement.getAttributeValue(new QName("source"));
                            String target =
                                    associationElement.getAttributeValue(new QName("target"));
                            associations.add(new Association(source, target, type));
                        }
                        associationElements =
                                associationDefinitions.getChildrenWithName(
                                        new QName("dependency"));
                        while (associationElements.hasNext()) {
                            OMElement associationElement = (OMElement) associationElements.next();
                            String source =
                                    associationElement.getAttributeValue(new QName("source"));
                            String target =
                                    associationElement.getAttributeValue(new QName("target"));
                            associations.add(new Association(source, target, "depends"));
                        }
                        configuration.setRelationshipDefinitions(associations.toArray(
                                new Association[associations.size()]));
                    }
                    OMElement uiConfigurations = configElement.getFirstChildWithName(
                            new QName("ui"));
                    if (uiConfigurations != null) {
                        configuration.setUIConfigurations(uiConfigurations);
                        OMElement uiListConfigurations = uiConfigurations.getFirstChildWithName(
                                new QName("list"));
                        if (uiListConfigurations != null) {
                            configuration.setUIListConfigurations(uiListConfigurations);
                        }
                    }
                    OMElement uiPermissions = configElement.getFirstChildWithName(
                            new QName("permissions"));
                    if (uiPermissions != null) {
                        Iterator permissionElements =
                                uiPermissions.getChildrenWithName(
                                        new QName("permission"));
                        List<ManagementPermission> managementPermissions =
                                new LinkedList<ManagementPermission>();
                        while (permissionElements.hasNext()) {
                            OMElement permissionElement = (OMElement) permissionElements.next();
                            OMElement nameElement =
                                    permissionElement.getFirstChildWithName(
                                            new QName("name"));
                            String name = (nameElement != null) ? nameElement.getText() : null;

                            OMElement idElement =
                                    permissionElement.getFirstChildWithName(
                                            new QName("id"));
                            String id = (idElement != null) ? idElement.getText() : null;
                            if (name != null && id != null) {
                                managementPermissions.add(new ManagementPermission(name, id));
                            }
                        }
                        configuration.setUIPermissions(managementPermissions.toArray(
                                new ManagementPermission[managementPermissions.size()]));
                    } else {
                        // if no permission definitions were present, define the default ones.
                        List<ManagementPermission> managementPermissions =
                                new LinkedList<ManagementPermission>();
                        String idPrefix = "/permission/admin/manage/resources/govern/" +
                                configuration.getKey();
                        managementPermissions.add(
                                new ManagementPermission(configuration.getPluralLabel(), idPrefix));
                        managementPermissions.add(
                                new ManagementPermission("Add", idPrefix + "/add"));
                        managementPermissions.add(
                                new ManagementPermission("List", idPrefix + "/list"));
                        managementPermissions.add(
                                new ManagementPermission(configuration.getPluralLabel(),
                                        "/permission/admin/configure/governance/" +
                                                configuration.getKey() + "-ui"
                                )
                        );
                        configuration.setUIPermissions(managementPermissions.toArray(
                                new ManagementPermission[managementPermissions.size()]));
                    }
                }
            } catch (XMLStreamException ignored) {
            } catch (NumberFormatException ignored) {
            }
            return configuration;
        }

        /**
         * Method to locate Governance Artifact configurations.
         *
         * @param registry the registry instance to run query on.
         * @return an array of resource paths.
         * @throws GovernanceException if the operation failed.
         */
        public static List<GovernanceArtifactConfiguration> findGovernanceArtifactConfigurations(
                Registry registry) throws RegistryException {
            String[] artifactConfigurations = findGovernanceArtifacts(
                    GovernanceConstants.GOVERNANCE_ARTIFACT_CONFIGURATION_MEDIA_TYPE, registry);
            List<GovernanceArtifactConfiguration> configurations =
                    new LinkedList<GovernanceArtifactConfiguration>();
            for (String artifactConfiguration : artifactConfigurations) {
                Resource resource = registry.get(artifactConfiguration);
                Object content = resource.getContent();
                String elementString;
                if (content instanceof String) {
                    elementString = (String) content;
                } else {
                    elementString = RegistryUtils.decodeBytes((byte[]) content);
                }
                configurations.add(getGovernanceArtifactConfiguration(elementString));
            }
            return configurations;
        }

        /**
         * Method to return the GovernanceArtifactConfiguration for a given media type
         *
         * @param registry the registry instance to run query on.
         * @param mediaType mediatype of the needed artifact configuration
         * @return GovernanceArtifactConfiguration
         * @throws RegistryException exception thorown if something goes wrong
         */
        public static GovernanceArtifactConfiguration getArtifactConfigurationByMediaType(Registry registry, String mediaType) throws RegistryException {
            List<GovernanceArtifactConfiguration> configurations = findGovernanceArtifactConfigurations(registry);

            for(GovernanceArtifactConfiguration configuration : configurations) {
                if(configuration.getMediaType().equals(mediaType)) {
                    return configuration;
                }
            }

            return null;
        }

        @SuppressWarnings("unused")
        public static void setTenantGovernanceSystemRegistry(final int tenantId) throws RegistryException {
            if (registryService != null) {
                tenantGovernanceSystemRegistry.set(
                        registryService.getGovernanceSystemRegistry(tenantId));
            }
        }

        @SuppressWarnings("unused")
        public static void unsetTenantGovernanceSystemRegistry() throws RegistryException {
            tenantGovernanceSystemRegistry.remove();
        }

        /**
         * Returns the system governance registry.
         *
         * @param registry the user registry.
         * @return the system registry.
         * @throws RegistryException throws if an error occurs
         */
        public static Registry getGovernanceSystemRegistry(Registry registry) throws RegistryException {

            if (tenantGovernanceSystemRegistry.get() != null) {
                return tenantGovernanceSystemRegistry.get();
            }

            if (registryService == null) {
                return null;
            }
            UserRegistry userRegistry;
            if (!(registry instanceof UserRegistry)) {
                return null;
            }
            userRegistry = (UserRegistry) registry;
            return registryService.getGovernanceSystemRegistry(userRegistry.getTenantId());
        }

        /**
         * Obtains the governance user registry from the given root registry instance. This is useful
         * when creating a governance user registry out of a remote client registry instance.
         *
         * @param registry the remote client registry instance.
         * @param username the name of the user to connect as.
         * @return the system registry.
         * @throws RegistryException throws if an error occurs
         */
        @SuppressWarnings("unused")
        public static Registry getGovernanceUserRegistry(Registry registry, String username)
                throws RegistryException {
            if (RegistryContext.getBaseInstance() == null) {
                RegistryContext.getBaseInstance(null, false);
            }
            return new UserRegistry(username, MultitenantConstants.SUPER_TENANT_ID, registry, null,
                    RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH);
        }

        /**
         * Obtains the governance user registry from the given root registry instance. This is useful
         * when creating a tenant aware governance user registry out of a remote client registry instance.
         *
         * @param registry registry the remote client registry instance.
         * @param username username the name of the user to connect as.
         * @param tenantId tenant id
         * @return the system registry
         * @throws RegistryException throws if an error occurs
         */
        public static Registry getGovernanceUserRegistry(Registry registry, String username, int tenantId)
                throws RegistryException {
            if (RegistryContext.getBaseInstance() == null) {
                RegistryContext.getBaseInstance(null, false);
            }
            return new UserRegistry(username, tenantId, registry, null,
                    RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH);
        }

        public static String parameterizeString(RequestContext requestContext, String parameterString) {
            String parameterizedString = parameterString;
            Pattern pattern = Pattern.compile("\\{@(\\w)*\\}");
            Matcher matcher = pattern.matcher(parameterString);
            GovernanceArtifact governanceArtifact;
            Registry registry = requestContext.getRegistry();
            String resourcePath = requestContext.getResourcePath().getPath();
            Set<String> matchSet = new HashSet<String>();

            while (matcher.find()) {
                matchSet.add(matcher.group());
            }

            for (String current : matchSet) {
                String name = current.substring(2, current.length() - 1);
                //To replace special values such as {@resourcePath}
                if (name.equals("resourcePath")) {
                    parameterizedString = parameterizedString.replaceAll("\\" + current.replace("}", "\\}"), resourcePath);
                }

                try {
                    governanceArtifact = GovernanceUtils.retrieveGovernanceArtifactByPath(requestContext.getSystemRegistry(), resourcePath);
                    if (governanceArtifact != null && governanceArtifact.getAttribute(name) != null) {
                        parameterizedString = parameterizedString.replaceAll("\\" + current.replace("}", "\\}"), governanceArtifact.getAttribute(name));
                    } else if (registry.get(resourcePath).getProperty(name) != null) {
                        parameterizedString = parameterizedString.replaceAll("\\" + current.replace("}", "\\}"), registry.get(resourcePath).getProperty(name));
                    } else {
                        log.error("Unable to locate the given value in properties or attributes");
                    }
                } catch (RegistryException e) {
                    log.error(e.getMessage(), e);
                }
            }

            return parameterizedString;

        }

        /**
         * Method to remove a governance artifact from the registry.
         *
         * @param registry   the registry instance.
         * @param artifactId the identifier of the artifact.
         * @throws GovernanceException if the operation failed.
         */
        public static void removeArtifact(Registry registry, String artifactId)
                throws GovernanceException {

            try {
                String path = getArtifactPath(registry, artifactId);
                if (registry.resourceExists(path)) {
                    deleteLifecycleHistoryFile(path, registry);
                    registry.delete(path);
                }
                ArtifactCache artifactCache =
                        ArtifactCacheManager.getCacheManager().getTenantArtifactCache(((UserRegistry) registry).getTenantId());
                if (artifactCache != null && path != null) {
                    artifactCache.invalidateArtifact(path);
                }
            } catch (RegistryException e) {
                String msg = "Error in deleting the the artifact id:" + artifactId + ".";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Method to obtain the artifact path of a governance artifact on the registry.
         *
         * @param registry   the registry instance.
         * @param artifactId the identifier of the artifact.
         * @return the artifact path.
         * @throws GovernanceException if the operation failed.
         */
        public static String getArtifactPath(Registry registry, String artifactId)
                throws GovernanceException {
        	Cache<String, String> cache;
            UserRegistry userRegistry = (UserRegistry) registry;
            //This is temp fix to identify remote calls. Will move cache initialization logic into registry core
            // with next major carbon(ex:4.5.0) release.
            if (userRegistry.getUserRealm() == null) {
                return getDirectArtifactPath(registry, artifactId);
            }
            try{
        		PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(userRegistry.getTenantId());
                String tenantDomain  = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(true);
                if (tenantDomain == null) {
                	tenantDomain = MultitenantUtils.getTenantDomain(((UserRegistry) registry).getUserName());
                }

                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
                cache  = RegistryUtils.getUUIDCache(RegistryConstants.UUID_CACHE_ID);
                if(cache.containsKey(artifactId)){
                    return cache.get(artifactId);
                }

        		try {

        			String sql = "SELECT REG_PATH_ID, REG_NAME FROM REG_RESOURCE WHERE REG_UUID = ?";

        			String[] result;
        			Map<String, String> parameter = new HashMap<String, String>();
        			parameter.put("1", artifactId);
        			parameter.put("query", sql);
        			result = registry.executeQuery(null, parameter).getChildren();

        			if (result != null && result.length == 1) {
        				cache.put(artifactId, result[0]);
        				return result[0];
        			}
        			return null;
        		} catch (RegistryException e) {
        			String msg =
        			             "Error in getting the path from the registry. Execute query failed with message : " +
        			                     e.getMessage();
        			log.error(msg, e);
        			throw new GovernanceException(msg, e);
        		}
    		} finally {
        		PrivilegedCarbonContext.endTenantFlow();
        	}
        }

        /**
         * Method to obtain the artifact path of a governance artifact on the registry.
         * without going through the UUID cache
         *
         * @param registry   the registry instance.
         * @param artifactId the identifier of the artifact.
         * @return the artifact path.
         * @throws GovernanceException if the operation failed.
         * TODO: This method is added since UUID cache cannot be properly implemented without proper
         * TODO: changes in the registry core. getArtifactPath needs to be moved into the registry core
         * TODO: and UUID caching should be handled by the cacheBackedRegistry and cachingHandler
         */
        public static String getDirectArtifactPath(Registry registry, String artifactId)
                throws GovernanceException {

            try {
                String sql = "SELECT REG_PATH_ID, REG_NAME FROM REG_RESOURCE WHERE REG_UUID = ?";

                String[] result;
                Map<String, String> parameter = new HashMap<String, String>();
                parameter.put("1", artifactId);
                parameter.put("query", sql);
                result = registry.executeQuery(null, parameter).getChildren();

                if (result != null && result.length == 1) {
                    return result[0];
                }
                return null;
            } catch (RegistryException e) {
                String msg = "Error in getting the path from the registry. Execute query failed with message : "
                        + e.getMessage();
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Retrieve all the governance artifact paths which associated with the given lifecycle
         *
         * @param registry  registry instance
         * @param lcName    lifecycle name
         * @param mediaType mediatype of the artifacts
         * @return String array of all the artifact paths
         * @throws GovernanceException if the operation failed.
         */
        public static String[] getAllArtifactPathsByLifecycle(Registry registry, String lcName, String mediaType) throws GovernanceException {
            String sql = "SELECT R.REG_PATH_ID, R.REG_NAME FROM REG_RESOURCE R, REG_PROPERTY PP, " +
                    "REG_RESOURCE_PROPERTY RP WHERE R.REG_VERSION=RP.REG_VERSION AND RP.REG_PROPERTY_ID=PP.REG_ID " +
                    "AND PP.REG_NAME = ?  AND  PP.REG_VALUE = ? AND R.REG_MEDIA_TYPE = ?";
            Map<String, String> parameter = new HashMap<String, String>();
            parameter.put("1", "registry.LC.name");
            parameter.put("2", lcName);
            parameter.put("3", mediaType);
            parameter.put("query", sql);

            try {
                return (String[]) registry.executeQuery(null, parameter).getContent();
            } catch (RegistryException e) {
                String msg = "Error occured while executing custom query";
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Retrieve all the governance artifact paths which associated with the given lifecycle in the given lifecycle state
         *
         * @param registry  registry instance
         * @param lcName    lifecycle name
         * @param lcState   lifecycle state
         * @param mediaType mediatype of the artifacts
         * @return String array of all the artifact paths
         * @throws GovernanceException if the operation failed.
         */
        public static String[] getAllArtifactPathsByLifecycleState(
                Registry registry, String lcName, String lcState, String mediaType) throws GovernanceException {
            String sql = "SELECT R.REG_PATH_ID, R.REG_NAME FROM REG_RESOURCE R, REG_PROPERTY PP, " +
                    "REG_RESOURCE_PROPERTY RP WHERE R.REG_VERSION=RP.REG_VERSION AND RP.REG_PROPERTY_ID=PP.REG_ID " +
                    "AND PP.REG_NAME = ?  AND  PP.REG_VALUE = ? AND R.REG_MEDIA_TYPE = ?";
            Map<String, String> parameter = new HashMap<String, String>();
            parameter.put("1", "registry.lifecycle." + lcName + ".state");
            parameter.put("2", lcState);
            parameter.put("3", mediaType);
            parameter.put("query", sql);

            try {
                return (String[]) registry.executeQuery(null, parameter).getContent();
            } catch (RegistryException e) {
                String msg = "Error occured while executing custom query";
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Method to obtain the value of a governance attribute.
         *
         * @param element   the payload element.
         * @param name      the attribute name.
         * @param namespace the namespace of the payload element.
         * @return the value of the attribute by the given name if it exists or an empty string.
         */
        public static String getAttributeValue(OMElement element, String name, String namespace) {
            String[] parts = name.split("_");
            OMElement attributeElement = element;
            for (String part : parts) {
                attributeElement = attributeElement.getFirstChildWithName(new QName(namespace, part));
                if (attributeElement == null) {
                    return "";
                }
            }
            return attributeElement.getText();
        }

        /**
         * @param registry the registry instance.
         * @return list of governance artifact identifiers.
         * @throws GovernanceException if the operation failed.
         * @deprecated Method to obtain all indexed governance artifact identifiers on the provided registry
         * instance.
         */
        public static String[] getAllArtifactIds(Registry registry)
                throws GovernanceException {
            throw new UnsupportedOperationException();
        }

        /**
         * @param registry the registry instance.
         * @return list of governance artifacts
         * @throws GovernanceException if the operation failed.
         * @deprecated Method to obtain all indexed governance artifacts on the provided registry instance.
         */
        @SuppressWarnings("unused")
        public static GovernanceArtifact[] getAllArtifacts(Registry registry)
                throws GovernanceException {
            throw new UnsupportedOperationException();
        }

        /**
         * Method to obtain a governance artifact on the registry.
         *
         * @param registry   the registry instance.
         * @param artifactId the identifier of the artifact.
         * @return the artifact.
         * @throws GovernanceException if the operation failed.
         */
        public static GovernanceArtifact retrieveGovernanceArtifactById(Registry registry,
                                                                        String artifactId)
                throws GovernanceException {
            String artifactPath = getArtifactPath(registry, artifactId);
            if (artifactPath == null) {
                String msg = "Governance artifact is not found for id: " + artifactId + ".";
                if (log.isDebugEnabled()) {
                    log.debug(msg);
                }
                return null;
            }
            return retrieveGovernanceArtifactByPath(registry, artifactPath);
        }

        /**
         * Method to obtain a governance artifact on the registry by the artifact path.
         *
         * @param registry     the registry instance.
         * @param artifactPath the path of the artifact.
         * @return the artifact.
         * @throws GovernanceException if the operation failed.
         */
        public static GovernanceArtifact retrieveGovernanceArtifactByPath(Registry registry,
                                                                          String artifactPath)
                throws GovernanceException {
            UserRegistry userRegistry = (UserRegistry) registry;
            String currentUser = userRegistry.getUserName();
            ArtifactCache artifactCache =
                    ArtifactCacheManager.getCacheManager().getTenantArtifactCache(userRegistry.getTenantId());
            if (artifactPath != null && artifactCache != null) {
                GovernanceArtifact governanceArtifact = artifactCache.getArtifact(artifactPath);
                if (governanceArtifact != null) {
                    return governanceArtifact;
                }
            }

            String artifactLC;
            String artifactLCState = null;
            try {
                Resource artifactResource;
                if (registry.resourceExists(artifactPath)) {
                    try {
                        artifactResource = registry.get(artifactPath);
                    } catch (AuthorizationFailedException e) {
                        // if the the user does not have access to the specified path, we are returning null.
                        if (log.isDebugEnabled()) {
                            String msg = "User does not have access to path " + artifactPath + ".";
                            log.debug(msg);
                        }
                        return null;
                    }
                    artifactLC = artifactResource.getProperty("registry.LC.name");

                    if (artifactLC != null) {
                        artifactLCState = artifactResource.getProperty("registry.lifecycle." + artifactLC + ".state");
                    }
                } else {
                    // if the artifact path doesn't exist we are returning null.
                    if (log.isDebugEnabled()) {
                        String msg = "The artifact path doesn't exists at " + artifactPath + ".";
                        log.debug(msg);
                    }
                    return null;
                }
                String artifactId =
                        artifactResource.getUUID();
                String mediaType = artifactResource.getMediaType();
                List<String> uniqueAttributes = getUniqueAttributesNames(registry, mediaType);
                if (GovernanceConstants.WSDL_MEDIA_TYPE
                        .equals(mediaType)) {
                    Wsdl wsdl = new WsdlImpl(artifactId, registry);
                    ((WsdlImpl) wsdl).setLcName(artifactLC);
                    ((WsdlImpl) wsdl).setLcState(artifactLCState);
                    ((WsdlImpl) wsdl).setArtifactPath(artifactPath);
                    ((WsdlImpl) wsdl).setUniqueAttributes(uniqueAttributes);
                    if (artifactCache != null) {
                        artifactCache.addArtifact(artifactPath, wsdl);
                    }
                    return wsdl;
                } else if (GovernanceConstants.SCHEMA_MEDIA_TYPE
                        .equals(mediaType)) {
                    Schema schema = new SchemaImpl(artifactId, registry);
                    ((SchemaImpl) schema).setLcName(artifactLC);
                    ((SchemaImpl) schema).setLcState(artifactLCState);
                    ((SchemaImpl) schema).setArtifactPath(artifactPath);
                    ((SchemaImpl) schema).setUniqueAttributes(uniqueAttributes);
                    if (artifactCache != null) {
                        artifactCache.addArtifact(artifactPath, schema);
                    }
                    return schema;
                } else if (GovernanceConstants.POLICY_XML_MEDIA_TYPE
                        .equals(mediaType)) {
                    Policy policy = new PolicyImpl(artifactId, registry);
                    ((PolicyImpl) policy).setLcName(artifactLC);
                    ((PolicyImpl) policy).setLcState(artifactLCState);
                    ((PolicyImpl) policy).setArtifactPath(artifactPath);
                    ((PolicyImpl) policy).setUniqueAttributes(uniqueAttributes);
                    if (artifactCache != null) {
                        artifactCache.addArtifact(artifactPath, policy);
                    }
                    return policy;
                } else if (GovernanceConstants.ENDPOINT_MEDIA_TYPE
                        .equals(mediaType)) {
                    Endpoint endpoint = new EndpointImpl(artifactId, registry);
                    ((EndpointImpl) endpoint).setLcName(artifactLC);
                    ((EndpointImpl) endpoint).setLcState(artifactLCState);
                    ((EndpointImpl) endpoint).setArtifactPath(artifactPath);
                    ((EndpointImpl) endpoint).setUniqueAttributes(uniqueAttributes);
                    if (artifactCache != null) {
                        artifactCache.addArtifact(artifactPath, endpoint);
                    }
                    return endpoint;
                } else if (mediaType != null && mediaType.matches("application/[a-zA-Z0-9.+-]+")) {
                    if (registry instanceof UserRegistry) {
                        List<GovernanceArtifactConfiguration> configurations =
                                artifactConfigurations.get(((UserRegistry) registry).getTenantId());
                        if (configurations != null) {
                            for (GovernanceArtifactConfiguration configuration :
                                    configurations) {
                                if (mediaType.equals(configuration.getMediaType())) {
                                    GenericArtifactImpl artifact;
                                    if (mediaType.matches("application/vnd\\.[a-zA-Z0-9.-]+\\+xml")) {
                                        byte[] contentBytes = (byte[]) artifactResource.getContent();
                                        if (contentBytes == null || contentBytes.length == 0) {
                                            throw new GovernanceException(
                                                    "Unable to read payload of governance artifact " +
                                                            "at path: " + artifactPath
                                            );
                                        }
                                        OMElement contentElement = buildOMElement(contentBytes);
                                        artifact = new GenericArtifactImpl(
                                                artifactId, contentElement,
                                                configuration.getArtifactNameAttribute(),
                                                configuration.getArtifactNamespaceAttribute(),
                                                configuration.getArtifactElementNamespace(),
                                                configuration.getMediaType());
                                        artifact.associateRegistry(registry);
                                        artifact.setArtifactPath(artifactPath);
                                    } else {
                                        artifact = new GenericArtifactImpl(artifactId, registry);
                                    }
                                    artifact.setLcState(artifactLCState);
                                    artifact.setLcName(artifactLC);
                                    artifact.setUniqueAttributes(uniqueAttributes);
                                    if (artifactCache != null) {
                                        artifactCache.addArtifact(artifactPath, artifact);
                                    }
                                    return artifact;
                                }
                            }
                        }
                    }
                }
                /*else if (GovernanceConstants.PEOPLE_MEDIA_TYPE.
                        equals(artifactResource.getMediaType())) {
                    // it is a peopleArtifact
                    byte[] contentBytes = (byte[]) artifactResource.getContent();
                    OMElement contentElement = null;
                    if (contentBytes != null) {
                        contentElement = buildOMElement(contentBytes);
                    }
                    String peopleGroup = CommonUtil.getPeopleGroup(contentElement);
                    PeopleArtifact peopleArtifact = null;
                    switch (PeopleGroup.valueOf(peopleGroup.toUpperCase())) {
                        case ORGANIZATION:
                            peopleArtifact = new Organization(artifactId, contentElement);
                            break;
                        case DEPARTMENT:
                            peopleArtifact = new Department(artifactId, contentElement);
                            break;
                        case PROJECT_GROUP:
                            peopleArtifact = new ProjectGroup(artifactId, contentElement);
                            break;
                        case PERSON:
                            peopleArtifact = new Person(artifactId, contentElement);
                            break;
                        default:
                            assert false;
                    }
                    peopleArtifact.associateRegistry(registry);
                    return peopleArtifact;
                }*/

            } catch (RegistryException e) {
                String msg = "Error in retrieving governance artifact by path. path: " + artifactPath + ".";
                //log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
            return null;
        }

        /**
         * Extracts all CheckListItemBeans from the resource
         * and update the lifecycle name and state of the artifact
         *
         * @param artifactResource resource related to the artifact
         * @param artifact         artifact which related to the resource
         * @param artifactLC       aspect name of which check list item bean is needed
         * @return CheckListItemBean array extracted from the resource
         * @throws GovernanceException GovernanceException  if the operation failed.
         */
        public static CheckListItemBean[] getAllCheckListItemBeans(Resource artifactResource, GovernanceArtifact artifact,
                String artifactLC) throws GovernanceException {
            String defaultLC = artifactResource.getProperty("registry.LC.name");

            String artifactLCState = artifactResource.getProperty("registry.lifecycle." + artifactLC + ".state");

            if (artifactLC.equals(defaultLC)) {
                ((GovernanceArtifactImpl) artifact).setLcState(artifactLCState);
            }

            ArrayList<CheckListItemBean> checkListItemList = new ArrayList<CheckListItemBean>();
            Properties lifecycleProps = artifactResource.getProperties();
            Set propertyKeys = lifecycleProps.keySet();
            for (Object propertyObj : propertyKeys) {
                String propertyKey = (String) propertyObj;

                String checkListPrefix = "registry.custom_lifecycle.checklist.";
                String checkListSuffix = ".item";

                if (propertyKey.startsWith(checkListPrefix) && propertyKey.endsWith(checkListSuffix) && propertyKey
                        .contains(GovernanceConstants.DOT + artifactLC + GovernanceConstants.DOT)) {
                    List<String> propValues = (List<String>) lifecycleProps.get(propertyKey);
                    CheckListItemBean checkListItem = new CheckListItemBean();
                    if (propValues != null && propValues.size() > 2) {
                        for (String param : propValues) {
                            if ((param.startsWith("status:"))) {
                                checkListItem.setStatus(param.substring(7));
                            } else if ((param.startsWith("name:"))) {
                                checkListItem.setName(param.substring(5));
                            } else if ((param.startsWith("value:"))) {
                                checkListItem.setValue(Boolean.parseBoolean(param.substring(6)));
                            } else if ((param.startsWith("order:"))) {
                                checkListItem.setOrder(Integer.parseInt(param.substring(6)));
                            }
                        }
                    }
                    checkListItemList.add(checkListItem);
                }
            }
            CheckListItemBean[] checkListItemBeans = new CheckListItemBean[checkListItemList.size()];
            if (checkListItemBeans.length > 0) {
                for (CheckListItemBean checkListItemBean : checkListItemList) {
                    checkListItemBeans[checkListItemBean.getOrder()] = checkListItemBean;
                }
                return checkListItemBeans;
            }
            return null;
        }

        /**
         * Extracts all ApproveItemBeans from the resource
         *
         * @param currentUser      current registry user
         * @param artifactResource resource related to the artifact
         * @param artifact         artifact related to the resource
         * @return ApproveItemBean array extracted from the resource
         * @throws GovernanceException if the operation failed.
         */
        public static ApproveItemBean[] getAllApproveItemBeans(
                String currentUser, Resource artifactResource, GovernanceArtifact artifact, String artifactLC) throws GovernanceException {
            String defaultLC = artifactResource.getProperty("registry.LC.name");
            String artifactLCState = artifactResource.getProperty("registry.lifecycle." + artifactLC + ".state");

            if (artifactLC.equals(defaultLC)) {
                ((GovernanceArtifactImpl) artifact).setLcState(artifactLCState);
            }
            if (artifactLC == null) {
                throw new GovernanceException("No lifecycle associated with the artifact path " +
                        artifactResource.getPath());
            }
            ((GovernanceArtifactImpl) artifact).setLcState(artifactLCState);
            ArrayList<ApproveItemBean> approveItemList = new ArrayList<ApproveItemBean>();
            Properties lifecycleProps = artifactResource.getProperties();
            Set propertyKeys = lifecycleProps.keySet();
            for (Object propertyObj : propertyKeys) {
                String propertyKey = (String) propertyObj;

                String votingPrefix = "registry.custom_lifecycle.votes.";
                String votingSuffix = ".vote";

                if (propertyKey.startsWith(votingPrefix) && propertyKey.endsWith(votingSuffix) && propertyKey
                        .contains(GovernanceConstants.DOT + artifactLC + GovernanceConstants.DOT)) {
                    List<String> propValues = (List<String>) lifecycleProps.get(propertyKey);
                    ApproveItemBean approveItemBean = new ApproveItemBean();
                    if (propValues != null && propValues.size() > 2) {
                        for (String param : propValues) {
                            if ((param.startsWith("status:"))) {
                                approveItemBean.setStatus(param.substring(7));
                            } else if ((param.startsWith("name:"))) {
                                approveItemBean.setName(param.substring(5));
                            } else if ((param.startsWith("votes:"))) {
                                approveItemBean.setRequiredVotes(Integer.parseInt(param.substring(6)));
                            } else if ((param.startsWith("current:"))) {
                                approveItemBean.setVotes(Integer.parseInt(param.substring(8)));
                            } else if ((param.startsWith("order:"))) {
                                approveItemBean.setOrder(Integer.parseInt(param.substring(6)));
                            } else if ((param.startsWith("users:"))) {
                                String users = param.substring(6);
                                if (!users.equals("")) {
                                    List<String> votedUsers = Arrays.asList(users.split(","));
                                    approveItemBean.setVoters(votedUsers);
                                    approveItemBean.setValue(votedUsers.contains(currentUser));
                                }
                            }
                        }
                    }
                    approveItemList.add(approveItemBean);
                }
            }

            ApproveItemBean[] approveItemBeans = new ApproveItemBean[approveItemList.size()];
            if (approveItemBeans.length > 0) {
                for (ApproveItemBean approveItemBean : approveItemList) {
                    approveItemBeans[approveItemBean.getOrder()] = approveItemBean;
                }
                return approveItemBeans;
            }
            return null;
        }

        /*public static String retrieveGovernanceArtifactPath(Registry registry,
                                                          String artifactId) throws GovernanceException {
            try {
                Resource govIndexResource = registry.get(GovernanceConstants.GOVERNANCE_ARTIFACT_INDEX_PATH);
                return govIndexResource.getProperty(artifactId);
            } catch (RegistryException e) {
                String msg = "Error in adding an entry for the governance artifact. uuid: " + artifactId + ".";
                log.error(msg);
                throw new GovernanceException(msg, e);
            }
        }*/

        /**
         * Method to register a governance artifact.
         *
         * @param registry     the registry instance.
         * @param artifactId   the identifier of the artifact.
         * @param artifactPath the path of the artifact.
         * @throws GovernanceException if the operation failed.
         */
    /*
        public static void addGovernanceArtifactEntry(Registry registry,
                                                      String artifactId,
                                                      String artifactPath) throws GovernanceException {
            try {
                Registry systemGovernanceRegistry = getGovernanceSystemRegistry(registry);
                if (systemGovernanceRegistry == null) {
                    systemGovernanceRegistry = registry;
                }
                Resource govIndexResource;
                if (systemGovernanceRegistry.resourceExists(
                        GovernanceConstants.GOVERNANCE_ARTIFACT_INDEX_PATH)) {
                    govIndexResource = systemGovernanceRegistry.get(
                            GovernanceConstants.GOVERNANCE_ARTIFACT_INDEX_PATH);
                } else {
                    govIndexResource = systemGovernanceRegistry.newResource();
                }
                govIndexResource.setProperty(artifactId, artifactPath);
                govIndexResource.setVersionableChange(false);
                systemGovernanceRegistry.put(GovernanceConstants.GOVERNANCE_ARTIFACT_INDEX_PATH,
                        govIndexResource);
            } catch (RegistryException e) {
                String msg =
                        "Error in adding an entry for the governance artifact. path: " + artifactPath +
                                ", uuid: " + artifactId + ".";
                log.error(msg);
                throw new GovernanceException(msg, e);
            }
        }
    */

        /**
         * Method to build an AXIOM element from a byte stream.
         *
         * @param content the stream of bytes.
         * @return the AXIOM element.
         * @throws GovernanceException if the operation failed.
         */
        public static OMElement buildOMElement(byte[] content) throws RegistryException {
            XMLStreamReader parser;
            try {
                XMLInputFactory factory = XMLInputFactory.newInstance();
                factory.setProperty(XMLInputFactory.IS_COALESCING, new Boolean(true));
                parser = factory.createXMLStreamReader(new StringReader(
                        RegistryUtils.decodeBytes(content)));
            } catch (XMLStreamException e) {
                String msg = "Error in initializing the parser to build the OMElement.";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }

            //create the builder
            StAXOMBuilder builder = new StAXOMBuilder(parser);
            //get the root element (in this case the envelope)

            return builder.getDocumentElement();
        }

        /**
         * Method to serialize an XML element into a string.
         *
         * @param element the XML element.
         * @return the corresponding String representation
         * @throws GovernanceException if the operation failed.
         */
        public static String serializeOMElement(OMElement element) throws GovernanceException {
            try {
                return element.toStringWithConsume();
            } catch (XMLStreamException e) {
                String msg = "Error in serializing the OMElement.";
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }

        /**
         * Method to convert the expression specified for storing the path with corresponding values
         * where the artifact is stored.
         *
         * @param pathExpression the expression specified for storing the path
         * @param artifact       the governance artifact
         * @param storagePath    the storage path of the artifact
         * @return the path with corresponding values where the artifact is stored
         * @throws GovernanceException if the operation failed.
         */
        public static String getPathFromPathExpression(String pathExpression,
                                                       GovernanceArtifact artifact,
                                                       String storagePath) throws GovernanceException {
            return getPathFromPathExpression(
                    pathExpression.replace("@{storagePath}", storagePath).replace("@{uuid}",
                            artifact.getId()), artifact
            );
        }

        /**
         * Method to convert the expression specified for storing the path with corresponding values
         * where the artifact is stored.
         *
         * @param pathExpression the expression specified for storing the path
         * @param artifact       the governance artifact
         * @return the path with corresponding values where the artifact is stored
         * @throws GovernanceException if the operation failed.
         */
        public static String getPathFromPathExpression(String pathExpression,
                                                       GovernanceArtifact artifact)
                throws GovernanceException {
            String output = replaceNameAndNamespace(pathExpression, artifact);
            String[] elements = output.split("@");
            for (int i = 1; i < elements.length; i++) {
                if (elements[i].indexOf("}") > 0 && elements[i].indexOf("{") == 0) {
                    String key = elements[i].split("}")[0].substring(1);
                    String artifactAttribute = artifact.getAttribute(key);
                    if (artifactAttribute != null) {
                        output = output.replace("@{" + key + "}", artifactAttribute);
                    } else {
                        String msg = "Value for required attribute " + key + " found empty.";
                        log.error(msg);
                        throw new GovernanceException(msg);
                    }
                }
            }
            return output;
        }

        /**
         * Method to compare the old and new artifact paths
         *
         * @param pathExpression the expression specified for storing the path
         * @param newArtifact    updated artifact
         * @param oldArtifact    existing artifact
         * @return whether the paths are same for old artifact and new artifact
         * @throws GovernanceException if the operation failed.
         */
        @SuppressWarnings("unused")
        public static boolean hasSamePath(String pathExpression,
                                          GovernanceArtifact newArtifact, GovernanceArtifact oldArtifact)
                throws GovernanceException {
            String output = replaceNameAndNamespace(pathExpression, newArtifact);
            String[] elements = output.split("@");
            for (int i = 1; i < elements.length; i++) {
                if (elements[i].indexOf("}") > 0 && elements[i].indexOf("{") == 0) {
                    String key = elements[i].split("}")[0].substring(1);
                    String oldArtifactAttribute = oldArtifact.getAttribute(key);
                    String newArtifactAttribute = newArtifact.getAttribute(key);
                    if (newArtifactAttribute != null) {
                        if (newArtifactAttribute.equals(oldArtifactAttribute)) {
                            continue;
                        } else {
                            return false;
                        }
                    } else {
                        String msg = "Value for required attribute " + key + " found empty.";
                        log.error(msg);
                        throw new GovernanceException(msg);
                    }
                }
            }
            return true;
        }

        /**
         * Method to convert the expression specified for storing the path with corresponding values
         * where the artifact is stored. This method will return multiple paths.
         *
         * @param pathExpression the expression specified for storing the path
         * @param artifact       the governance artifact
         * @return the paths with corresponding values where the artifact is stored
         * @throws GovernanceException if the operation failed.
         */
        public static String[] getPathsFromPathExpression(String pathExpression,
                                                          GovernanceArtifact artifact)
                throws GovernanceException {
            String expression = replaceNameAndNamespace(pathExpression, artifact);
            String[] elements = expression.split("@");
            for (int i = 1; i < elements.length; i++) {
                if (!(elements[i].indexOf(":") > 0) &&
                        elements[i].indexOf("}") > 0 && elements[i].indexOf("{") == 0) {
                    String key = elements[i].split("}")[0].substring(1);
                    String artifactAttribute = artifact.getAttribute(key);
                    if (artifactAttribute != null) {
                        expression = expression.replace("@{" + key + "}", artifactAttribute);
                    }
                }
            }
            List<String> output = fixExpressionForMultiplePaths(artifact, expression);
            return output.toArray(new String[output.size()]);
        }

        private static List<String> fixExpressionForMultiplePaths(GovernanceArtifact artifact,
                                                                  String expression)
                throws GovernanceException {
            if (!expression.contains("@")) {
                return Collections.singletonList(expression);
            }
            List<String> output = new LinkedList<String>();
            String[] elements = expression.split("@");
            for (int i = 1; i < elements.length; i++) {
                if (elements[i].indexOf("}") > 0 && elements[i].indexOf("{") == 0) {
                    String key = elements[i].split("}")[0].substring(1).split(":")[0];
                    String[] artifactAttributes = artifact.getAttributes(key);
                    if (artifactAttributes != null) {
                        for (String artifactAttribute : artifactAttributes) {
                            String[] parts = artifactAttribute.split(":");
                            if (parts.length > 1) {
                                output.addAll(fixExpressionForMultiplePaths(artifact,
                                        expression.replace("@{" + key + ":key}", parts[0])
                                                .replace("@{" + key + ":value}", parts[1])));
                            }
                        }
                    }
                    break;
                }
            }
            return output;
        }

        private static String replaceNameAndNamespace(String pathExpression,
                                                      GovernanceArtifact artifact) {
            String output = pathExpression;
            QName qName = artifact.getQName();

            if (qName != null) {
                output = output.replace("@{name}", qName.getLocalPart());
                String replacement =
                        CommonUtil.derivePathFragmentFromNamespace(qName.getNamespaceURI());
                if (replacement.startsWith("/")) {
                    replacement = replacement.substring(1);
                }
                if (replacement.endsWith("/")) {
                    replacement = replacement.substring(0, replacement.length() - 1);
                }
                output = output.replace("@{namespace}", replacement);
            }
            return output;
        }

        /**
         * Method to obtain all available aspects for the given tenant.
         *
         * @return list of available aspects.
         * @throws RegistryException if the operation failed.
         */
        public static String[] getAvailableAspects() throws RegistryException {
            int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
            Registry systemRegistry = registryService.getConfigSystemRegistry(tenantId);
            String[] aspectsToAdd = systemRegistry.getAvailableAspects();
            if (aspectsToAdd == null) {
                return new String[0];
            }
            List<String> lifecycleAspectsToAdd = new LinkedList<String>();
            boolean isTransactionStarted = false;
            String tempResourcePath = "/governance/lcm/" + UUIDGenerator.generateUUID();
            for (String aspectToAdd : aspectsToAdd) {
                if (systemRegistry.getRegistryContext().isReadOnly()) {
                    lifecycleAspectsToAdd.add(aspectToAdd);
                    continue;
                }
                Map<String, Boolean> aspectsMap;
                if (!lifecycleAspects.containsKey(tenantId)) {
                    synchronized (ASPECT_MAP_LOCK) {
                        if (!lifecycleAspects.containsKey(tenantId)) {
                            aspectsMap = new HashMap<String, Boolean>();
                            lifecycleAspects.put(tenantId, aspectsMap);
                        } else {
                            aspectsMap = lifecycleAspects.get(tenantId);
                        }
                    }
                } else {
                    aspectsMap = lifecycleAspects.get(tenantId);
                }
                Boolean isLifecycleAspect = aspectsMap.get(aspectToAdd);
                if (isLifecycleAspect == null) {
                    if (!isTransactionStarted) {
                        systemRegistry.beginTransaction();
                        isTransactionStarted = true;
                    }
                    systemRegistry.put(tempResourcePath, systemRegistry.newResource());
                    systemRegistry.associateAspect(tempResourcePath, aspectToAdd);
                    Resource r = systemRegistry.get(tempResourcePath);
                    Properties props = r.getProperties();
                    Set keys = props.keySet();
                    for (Object key : keys) {
                        String propKey = (String) key;
                        if (propKey.startsWith("registry.lifecycle.")
                                || propKey.startsWith("registry.custom_lifecycle.checklist.")) {
                            isLifecycleAspect = Boolean.TRUE;
                            break;
                        }
                    }
                    if (isLifecycleAspect == null) {
                        isLifecycleAspect = Boolean.FALSE;
                    }
                    aspectsMap.put(aspectToAdd, isLifecycleAspect);
                }
                if (isLifecycleAspect) {
                    lifecycleAspectsToAdd.add(aspectToAdd);
                }
            }
            if (isTransactionStarted) {
                systemRegistry.delete(tempResourcePath);
                systemRegistry.rollbackTransaction();
            }
            return lifecycleAspectsToAdd.toArray(new String[lifecycleAspectsToAdd.size()]);
        }

        /**
         * Method to obtain a path from a qualified name.
         *
         * @param qName the qualified name.
         * @return the corresponding path.
         */
        @SuppressWarnings("unused")
        public static String derivePathFromQName(QName qName) {
            String serviceName = qName.getLocalPart();
            String serviceNamespace = qName.getNamespaceURI();
            return (serviceNamespace == null ?
                    "" : CommonUtil.derivePathFragmentFromNamespace(serviceNamespace)) + serviceName;
        }

        /**
         * Obtain a name that can represent a URL.
         *
         * @param url the URL.
         * @return the name.
         */
        public static String getNameFromUrl(String url) {
            int slashIndex = url.lastIndexOf('/');
            if (slashIndex == -1) {
                return url;
            }
            if (slashIndex == url.length() - 1) {
                return url.substring(0, url.length() - 1);
            }
            return url.substring(slashIndex + 1);
        }

        @SuppressWarnings("unchecked")
        public static List<OMElement> evaluateXPathToElements(String expression,
                                                              OMElement root) throws JaxenException {

            String[] wsdlPrefixes = {
                    "wsdl", "http://schemas.xmlsoap.org/wsdl/",
                    "wsdl2", "http://www.w3.org/ns/wsdl",
                    "xsd", "http://www.w3.org/2001/XMLSchema",
                    "soap", "http://schemas.xmlsoap.org/wsdl/soap/",
                    "soap12", "http://schemas.xmlsoap.org/wsdl/soap12/",
                    "http", "http://schemas.xmlsoap.org/wsdl/http/",
            };
            AXIOMXPath xpathExpression = new AXIOMXPath(expression);

            for (int j = 0; j < wsdlPrefixes.length; j++) {
                xpathExpression.addNamespace(wsdlPrefixes[j++], wsdlPrefixes[j]);
            }
            return (List<OMElement>) xpathExpression.selectNodes(root);
        }

        /**
         * Method to associate an aspect with a given resource on the registry.
         *
         * @param path     the path of the resource.
         * @param aspect   the aspect to add.
         * @param registry the registry instance on which the resource is available.
         * @throws RegistryException if the operation failed.
         */
        public static void associateAspect(String path, String aspect, Registry registry)
                throws RegistryException {

            try {
                registry.associateAspect(path, aspect);

                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", aspect);
                    registry.put(path, resource);
                }

            } catch (RegistryException e) {

                String msg = "Failed to associate aspect with the resource " +
                        path + ". " + e.getMessage();
                log.error(msg, e);
                throw new RegistryException(msg, e);
            }
        }

        /**
         * Method to remove an aspect from a given resource on the registry.
         *
         * @param path     the path of the resource.
         * @param aspect   the aspect to be removed.
         * @param registry the registry instance on which the resource is available.
         * @throws RegistryException if the operation failed.
         */
        public static void removeAspect(String path, String aspect, Registry registry)
                throws RegistryException {

            try {
                /* set all the variables to the resource */
                Resource resource = registry.get(path);
                Properties props = resource.getProperties();
                //List<Property> propList = new ArrayList<Property>();
                Iterator iKeys = props.keySet().iterator();
                ArrayList<String> propertiesToRemove = new ArrayList<String>();

                while (iKeys.hasNext()) {
                    String propKey = (String) iKeys.next();

                    if (isStartsWithRegistry(propKey) && propKey.contains(aspect)) {
                        propertiesToRemove.add(propKey);
                    }
                }

                for (String propertyName : propertiesToRemove) {
                    resource.removeProperty(propertyName);
                }

                // This is needed as we are not removing all the aspects, which was removed when the current method is called
                resource.removeAspect(aspect);

                if(resource.getProperty("registry.LC.name").equals(aspect)) {
                    resource.removeProperty("registry.LC.name");
                    if(resource.getAspects().size() > 0) {
                        resource.setProperty("registry.LC.name", resource.getAspects().get(0));
                    }
                }

                registry.put(path, resource);

            } catch (RegistryException e) {

                String msg = "Failed to remove aspect " + aspect +
                        " on resource " + path + ". " + e.getMessage();
                log.error(msg, e);
                throw new RegistryException(msg, e);
            }
        }

        private static boolean isStartsWithRegistry(String propKey) {
            return (propKey.startsWith(GovernanceConstants.REGISTRY_CUSTOM_LC_VOTES_PROPERTY)
                    || propKey.startsWith(GovernanceConstants.REGISTRY_CUSTOM_LC_USER_PROPERTY)
                    || propKey.startsWith(GovernanceConstants.REGISTRY_CUSTOM_LC_CHECKLIST_PROPERTY)
                    || propKey.startsWith(GovernanceConstants.REGISTRY_LIFECYCLE_NAME_PROPERTY)
                    || propKey.startsWith(GovernanceConstants.REGISTRY_LIFECYCLE)
                    || propKey.startsWith(GovernanceConstants.REGISTRY_ASPECTS_PROPERTY));
        }

        public static AttributeSearchService getAttributeSearchService() {
            return attributeSearchService;
        }

        public static void setAttributeSearchService(AttributeSearchService attributeSearchService) {
            GovernanceUtils.attributeSearchService = attributeSearchService;
        }

        public static TermsSearchService getTermsSearchService() {
            return termsSearchService;
        }

        public static void setTermsSearchService(TermsSearchService termsSearchService) {
            GovernanceUtils.termsSearchService = termsSearchService;
        }

        public static ContentSearchService getContentSearchService() {
            return contentSearchService;
        }

        public static void setContentSearchService(ContentSearchService contentSearchService) {
            GovernanceUtils.contentSearchService = contentSearchService;
        }

        public static TermsQuerySearchService getTermsQuerySearchService() {
            return termsQuerySearchService;
        }

        public static void setTermsQuerySearchService(TermsQuerySearchService termsQuerySearchService) {
            GovernanceUtils.termsQuerySearchService = termsQuerySearchService;
        }

        /**
         * Method to make an aspect to default.
         * @param path path of the resource
         * @param aspect   the aspect to be removed.
         * @param registry registry instance to be used
         */
        public static void setDefaultLifeCycle(String path, String aspect, Registry registry) throws RegistryException {
            Resource resource = registry.get(path);
            if(resource != null) {
                resource.setProperty("registry.LC.name", aspect);
                registry.put(path, resource);
            }
        }

        /**
         * Returns a list of governance artifacts found by searching indexes. This method requires an instance of an
         * attribute search service.
         *
         * @param criteria the search criteria
         * @param registry the governance registry instance
         * @return search result
         * @throws GovernanceException if the operation failed
         */
        public static List<GovernanceArtifact> findGovernanceArtifacts(Map<String, List<String>> criteria,
                                                                       Registry registry, String mediaType)
                throws GovernanceException {
            if (getAttributeSearchService() == null) {
                throw new GovernanceException("Attribute Search Service not Found");
            }
            List<GovernanceArtifact> artifacts = new ArrayList<GovernanceArtifact>();
            Map<String, String> fields = new HashMap<String, String>();
            if (mediaType != null) {
                fields.put("mediaType", mediaType);
            }
            for (Map.Entry<String, List<String>> e : criteria.entrySet()) {
                StringBuilder builder = new StringBuilder();
                for (String referenceValue : e.getValue()) {
                    if (referenceValue != null && !"".equals(referenceValue)) {
                        String referenceValueModified = referenceValue;
                        if(referenceValueModified.contains(" ")) {
                            referenceValueModified = referenceValueModified.replace(" ", "\\ ");
                        }
                        builder.append(referenceValueModified.toLowerCase()).append(",");
                    }
                }
                if (builder.length() > 0) {
                    fields.put(e.getKey(), builder.substring(0, builder.length() - 1));
                }
            }

            try {
                ResourceData[] results = getAttributeSearchService().search(fields);
                int errorCount = 0; // We use this to check how many errors occurred.
                for (ResourceData result : results) {
                    GovernanceArtifact governanceArtifact = null;
                    String path = result.getResourcePath().substring(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH.length());
                    try {
                        governanceArtifact = retrieveGovernanceArtifactByPath(registry, path);
                    } catch (GovernanceException e) {
                        // We do not through any exception here. Only logging is done.
                        // We increase the error count for each error. If all the paths failed, then we throw an error
                        errorCount++;
                        log.error("Error occurred while retrieving governance artifact by path : " + path, e);
                    }
                    if (governanceArtifact != null) {
                        artifacts.add(governanceArtifact);
                    }
                } if (errorCount != 0 && errorCount == results.length) {
                    // This means that all the paths have failed. So we throw an error.
                    throw new GovernanceException("Error occurred while retrieving all the governance artifacts");
                }
            } catch (RegistryException e) {
                throw new GovernanceException("Unable to search by attribute", e);
            }
            return artifacts;
        }

        private static String buildSearchCriteria(String criteria, Registry registry, String mediaType,
                Map<String, String> possibleProperties, Map<String, String> fields, boolean hasOneProperty)
                throws GovernanceException {
            String editedCriteria = "";
            GovernanceArtifactConfiguration artifactConfiguration;
            try {
                if (criteria != null) {
                    //decode search query
                    editedCriteria = URLDecoder.decode(criteria, "utf-8");
                }
            } catch (UnsupportedEncodingException e) {
                throw new GovernanceException("Error occurred while decoding the query params");
            }

            if (mediaType != null && !"".equals(mediaType)) {
                fields.put("mediaType", mediaType);
            } else if("".equals(criteria)) {
                return null;
            }

            try {
                artifactConfiguration = findGovernanceArtifactConfigurationByMediaType(mediaType, registry);
            } catch (RegistryException e) {
                throw new GovernanceException(e);
            }

            List<String> possibleKeys = Arrays.asList("createdAfter", "createdBefore", "updatedAfter", "updatedBefore", "author", "author!", "associationType", "associationDest",
                    "updater", "updater!", "tags", "taxonomy", "content", "mediaType", "mediaType!", "lcName", "lcState");

            List<String> finalTempList = new ArrayList<>();
            if (StringUtils.isNotEmpty(criteria)) {
                String[] tempList = criteria.split("&");
                for (int i = 0; i < tempList.length; i++) {
                    try {
                        finalTempList.add(URLDecoder.decode(tempList[i], "utf-8"));
                    } catch (UnsupportedEncodingException e) {
                        throw new GovernanceException("Error occurred while decoding the query params");
                    }
                }
            }
            for(String temp : finalTempList) {
                String[] subParts = temp.split("=");
                if(subParts.length != 2) {
                    String value = subParts[0].toLowerCase();
                    if(value.contains(" ")) {
                        value = value.replace(" ", "\\ ");
                    }
                    fields.put("overview_name", value);
                } else {
                    if(possibleKeys.contains(subParts[0])) {
                        switch(subParts[0]) {
                            case "author!":
                                fields.put(subParts[0].substring(0, subParts[0].length() - 1), subParts[1].toLowerCase());
                                fields.put("authorNameNegate", "on");
                                break;
                            case "updater!":
                                fields.put(subParts[0].substring(0, subParts[0].length() - 1), subParts[1].toLowerCase());
                                fields.put("updaterNameNegate", "on");
                                break;
                            case "mediaType!":
                                fields.put(subParts[0].substring(0, subParts[0].length() - 1), subParts[1].toLowerCase());
                                fields.put("mediaTypeNegate", "on");
                                break;
                            case "tags":
                                fields.put(subParts[0], subParts[1]);
                                break;
                            case "associationType":
                            case "taxonomy":
                                String taxaValue = subParts[1].toLowerCase().replaceAll("\\* (and|AND) \\*", "* && *").
                                        replaceAll("\\) (and|AND) \\(", ") && (").replaceAll("\\* (and|AND) \\(", "* && (").
                                        replaceAll("\\) (and|AND) \\*", ") && *");
                                fields.put(subParts[0], taxaValue);
                                //edit taxa value in the edited criteria for content search
                                editedCriteria = editedCriteria.replace(subParts[1], taxaValue);
                                break;
                            case "associationDest":
                                fields.put(subParts[0], subParts[1]);
                                break;
                            default:
                                String value = subParts[1].toLowerCase();
                                value = buildSearchValue(value);
                                fields.put(subParts[0], value);
                                // lowercase to query value for the content search
                                editedCriteria = editedCriteria.replace(subParts[1], value);
                                break;
                        }
                    } else if(subParts[0].equals("comments")){
                        fields.put("commentWords", subParts[1].toLowerCase());
                        // change the key and lowercase to query value for the content search
                        editedCriteria = editedCriteria.replace("comments", "commentWords");
                        editedCriteria = editedCriteria.replace(subParts[1], subParts[1].toLowerCase());
                    } else {
                        if(subParts[0].contains(":")) {
                            String value = subParts[1].toLowerCase();
                            value = buildSearchValue(value);
                            String[] tableParts = subParts[0].split(":");
                            if ("overview".equals(tableParts[0])) {
                                if (!hasOneProperty || possibleProperties.size() == 0) {
                                    possibleProperties.put(tableParts[1], value);
                                }
                                //add new query parameter to support properties search.
                                String overviewField = tableParts[1] + ":" + value + " OR ";
                                editedCriteria = new StringBuilder(editedCriteria).insert(editedCriteria.lastIndexOf(subParts[0]), overviewField).toString();
                            }
                            fields.put(subParts[0].replace(":", "_"), value);
                            // change the key and lowercase to query value for the content search
                            editedCriteria = editedCriteria.replace(subParts[0], subParts[0].replace(":", "_"));
                            editedCriteria = editedCriteria.replace(subParts[1], value);
                        } else {
                            String value = subParts[1].toLowerCase();
                            value = buildSearchValue(value);
                            if(!subParts[0].equals("name")) {
                                if (!hasOneProperty || possibleProperties.size() == 0) {
                                    possibleProperties.put(subParts[0], value);
                                }
                                fields.put(OVERVIEW + UNDERSCORE + subParts[0], value);
                                editedCriteria = editedCriteria.replace(subParts[1], value);
                                //add new query parameter to search in both resource properties and metadata content
                                String overviewField = OVERVIEW + UNDERSCORE + subParts[0] + ":" + value + " OR ";
                                editedCriteria = new StringBuilder(editedCriteria).insert(editedCriteria.lastIndexOf(subParts[0]), overviewField).toString();
                            } else {
                                if (artifactConfiguration != null) {
                                    fields.put(artifactConfiguration.getArtifactNameAttribute(), value);
                                    // change the key and lowercase to query value for the content search
                                    editedCriteria = editedCriteria.replace(subParts[0], artifactConfiguration.getArtifactNameAttribute());
                                    editedCriteria = editedCriteria.replace(subParts[1], value);
                                } else {
                                    fields.put(OVERVIEW + UNDERSCORE + subParts[0], value);
                                    editedCriteria = editedCriteria.replace(subParts[0], OVERVIEW + UNDERSCORE + subParts[0]);
                                    editedCriteria = editedCriteria.replace(subParts[1], value);
                                }
                            }
                        }
                    }
                }
            }

            return editedCriteria;
        }

        private static String buildSearchValue(String value) {
            if (value.contains(" or ")) {
                String[] values = value.split(" or ");
                for (int i = 0; i < values.length; i++) {
                    if (!values[i].contains(" or")) {
                        values[i] = values[i].trim().replace(" ", "\\ ");
                    }
                }
                value = StringUtils.join(values, " OR ");
            } else if (value.contains(" and ")) {
                String[] values = value.split(" and ");
                for (int i = 0; i < values.length; i++) {
                    if (!values[i].contains(" and")) {
                        values[i] = values[i].trim().replace(" ", "\\ ");
                    }
                }
                value = StringUtils.join(values, " AND ");
            } else if (value.contains(" ") && !value.contains(" or")) {
                value = value.replace(" ", "\\ ");
            }
            return value;
        }

        /**
         * @param criteria query string that should be searched for
         * @param registry the governance registry instance
         * @param mediaType media type to be matched for search. Media type can be specified in the query string too
         * @return The list of artifacts. null if the media type and string is empty.
         * @throws GovernanceException thrown when an error occurs
         */
        public static List<GovernanceArtifact> findGovernanceArtifacts(String criteria, Registry registry, String mediaType)
                throws GovernanceException {
            return findGovernanceArtifacts(criteria, registry, mediaType, false);
        }

        /**
         * @param criteria       query string that should be searched for
         * @param registry       the governance registry instance
         * @param mediaType      media type to be matched for search. Media type can be specified in the query string too.
         * @param hasOneProperty To specify whether search criteria contains one property.
         * @return The list of artifacts. null if the media type and string is empty.
         * @throws GovernanceException thrown when an error occurs
         */
        public static List<GovernanceArtifact> findGovernanceArtifacts(String criteria, Registry registry, String mediaType,
                boolean hasOneProperty) throws GovernanceException {
            Map<String, String> fields = new HashMap<>();
            Map<String, String> possibleProperties = new HashMap<>();
            //maintain search query to support OR via content search
            String editedCriteria = buildSearchCriteria(criteria, registry, mediaType, possibleProperties, fields,
                    hasOneProperty);

            if (editedCriteria != null && (editedCriteria.contains(FIELDS_OR_WILD_SEARCH) || editedCriteria.contains(FIELDS_OR_SEARCH))) {
                editedCriteria = editedCriteria.replace(FIELDS_OR_WILD_SEARCH, REPLACEMENT_OR_WILD_SEARCH);
                editedCriteria = editedCriteria.replace(FIELDS_AND_WILD_SEARCH, REPLACEMENT_AND_WILD_SEARCH);
                editedCriteria = editedCriteria.replace(FIELDS_OR_SEARCH, REPLACEMENT_OR_SEARCH);
                editedCriteria = editedCriteria.replace(FIELDS_AND_SEARCH, REPLACEMENT_AND_SEARCH);
                editedCriteria = editedCriteria.replace(SYMBOL_AND, REPLACEMENT_SYMBOL_AND);
                editedCriteria = editedCriteria.replace(SYMBOL_EQUAL, SYMBOL_COLON);
                editedCriteria = "(" + editedCriteria + ") AND mediaType:" + mediaType;
                log.debug("Content OR search | Search Criteria::: " + editedCriteria);
                return performContentSearch(editedCriteria, registry);
            }

            List<GovernanceArtifact> attributeSearchResults = performAttributeSearch(fields, registry);

            // Following check is done since Attribute Search service only has a way to search one property at a time
            if(possibleProperties.size() == 1) {

                int paginationSizeAtt = 0;
                if (PaginationContext.getInstance() !=  null) {
                    paginationSizeAtt = PaginationContext.getInstance().getLength();
                }

                for(Map.Entry<String, String> entry : possibleProperties.entrySet()) {
                    String propertyName = entry.getKey();
                    fields.remove("overview_" + propertyName);
                    fields.put("propertyName", propertyName);
                    fields.put("rightPropertyValue", entry.getValue());
                    fields.put("rightOp", "eq");
                }

                List<GovernanceArtifact> propertySearchResults = performAttributeSearch(fields, registry);

                Set<GovernanceArtifact> removeDuplicate = new TreeSet<>(new Comparator<GovernanceArtifact>() {
                    public int compare(GovernanceArtifact artifact1, GovernanceArtifact artifact2) {
                        return artifact1.getId().compareTo(artifact2.getId());
                    }
                });
                removeDuplicate.addAll(attributeSearchResults);
                removeDuplicate.addAll(propertySearchResults);

                List<GovernanceArtifact> mergeListWithoutDuplicates = new ArrayList<>();
                mergeListWithoutDuplicates.addAll(removeDuplicate);

                Set<GovernanceArtifact> set = new TreeSet<>(new Comparator<GovernanceArtifact>() {
                    public int compare(GovernanceArtifact artifact1, GovernanceArtifact artifact2) {
                        PaginationContext paginationContext = PaginationContext.getInstance();
                        if (paginationContext != null) {
                            String sortBy = paginationContext.getSortBy();
                            String sortOrder = paginationContext.getSortOrder();
                            try {
                                if (StringUtils.isNotBlank(sortBy) && StringUtils.isNotBlank(sortOrder)) {
                                    switch (sortOrder) {
                                    case "ASC":
                                        return comparison(artifact1.getAttribute(sortBy), artifact2.getAttribute(sortBy),
                                                sortBy);
                                    case "DES":
                                    case "DESC":
                                        return comparison(artifact2.getAttribute(sortBy), artifact1.getAttribute(sortBy),
                                                sortBy);
                                    default:
                                        return artifact1.getId().compareTo(artifact2.getId());
                                    }
                                }
                            } catch (GovernanceException e) {
                                log.error("Error when trying to compare the sortBy attributes of the returned artifacts.",
                                        e);
                            }
                        }

                        return artifact1.getId().compareTo(artifact2.getId());
                    }

                    private int comparison(String value1, String value2, String sortBy) throws GovernanceException {
                        //If sortBy is equal to a date/time attribute, preserve the order returned from the solr client.
                        if ("createdDate".equals(sortBy) || "lastUpdatedDate".equals(sortBy)) {
                            return 1;
                        }
                        //Else if sortBy an attribute
                        if (StringUtils.isEmpty(value1)) {
                            throw new GovernanceException("Artifact does not contain the attribute " + sortBy);
                        }
                        int comparisonValue = value1.compareTo(value2);
                        if (comparisonValue == 0) {
                            return -1;
                        }
                        return comparisonValue;
                    }
                });

                set.addAll(mergeListWithoutDuplicates);

                List<GovernanceArtifact> sortedList = new ArrayList<>();
                sortedList.addAll(set);

                if (paginationSizeAtt != 0 && PaginationContext.getInstance() != null){
                    int reduce = 0;
                    if (mergeListWithoutDuplicates.size() != 0 && mergeListWithoutDuplicates.size() !=attributeSearchResults.size() + propertySearchResults.size()){
                        reduce = attributeSearchResults.size() + propertySearchResults.size() - mergeListWithoutDuplicates.size();
                    }
                    int paginationSizePros = PaginationContext.getInstance().getLength();
                    PaginationContext.getInstance().setLength(paginationSizeAtt +paginationSizePros - reduce);
                }
                return sortedList;
            }

            return attributeSearchResults;
        }

        private static List<GovernanceArtifact> performAttributeSearch(Map<String, String> fields, Registry registry) throws GovernanceException {
            if (getAttributeSearchService() == null) {
                throw new GovernanceException("Attribute Search Service not Found");
            }

            List<GovernanceArtifact> artifacts = new ArrayList<GovernanceArtifact>();

            try {
                ResourceData[] results = getAttributeSearchService().search(fields);

                int errorCount = 0; // We use this to check how many errors occurred.

                for (ResourceData result : results) {
                    GovernanceArtifact governanceArtifact = null;
                    String path = result.getResourcePath().substring(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH.length());
                    try {
                        governanceArtifact = retrieveGovernanceArtifactByPath(registry, path);
                    } catch (GovernanceException e) {
                        // We do not through any exception here. Only logging is done.
                        // We increase the error count for each error. If all the paths failed, then we throw an error
                        errorCount++;
                        log.error("Error occurred while retrieving governance artifact by path : " + path, e);
                    }
                    if (governanceArtifact != null) {
                        artifacts.add(governanceArtifact);
                    }
                } if (errorCount != 0 && errorCount == results.length) {
                    // This means that all the paths have failed. So we throw an error.
                    throw new GovernanceException("Error occurred while retrieving all the governance artifacts");
                }
            } catch (RegistryException e) {
                throw new GovernanceException("Unable to search by attribute", e);
            }
            return artifacts;
        }

        /**
         * Method returns artifacts results list of registry content search
         *
         * @param criteria search criteria
         * @param registry registry
         * @return search results
         * @throws GovernanceException
         */
        private static List<GovernanceArtifact> performContentSearch(String criteria, Registry registry) throws GovernanceException {
            if (getContentSearchService() == null) {
                throw new GovernanceException("Content Search Service not Found");
            }

            List<GovernanceArtifact> artifacts = new ArrayList<>();

            try {
                ResourceData[] results = getContentSearchService().search(criteria);
                int errorCount = 0; // We use this to check how many errors occurred.
                for (ResourceData result : results) {
                    GovernanceArtifact governanceArtifact = null;
                    String path = result.getResourcePath().substring(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH.length());
                    try {
                        governanceArtifact = retrieveGovernanceArtifactByPath(registry, path);
                    } catch (GovernanceException e) {
                        // We do not through any exception here. Only logging is done.
                        // We increase the error count for each error. If all the paths failed, then we throw an error
                        errorCount++;
                        log.error("Error occurred while retrieving governance artifact by path : " + path, e);
                    }
                    if (governanceArtifact != null) {
                        artifacts.add(governanceArtifact);
                    }
                }
                if (errorCount != 0 && errorCount == results.length) {
                    // This means that all the paths have failed. So we throw an error.
                    throw new GovernanceException("Error occurred while retrieving all the governance artifacts");
                }
            } catch (RegistryException e) {
                throw new GovernanceException("Unable to search by attribute", e);
            }
            return artifacts;
        }

        /**
         * Find all possible terms and its count for the given facet field and query criteria
         * @param criteria the filter criteria to be matched
         * @param facetField field used for faceting : required
         * @param mediaType artifact type need to filter : optional
         * @param authRequired authorization required flag
         * @return term results
         * @throws GovernanceException
         */
        public static List<TermData> getTermDataList(Map<String, List<String>> criteria, String facetField, String mediaType, boolean authRequired) throws GovernanceException {
            if (getTermsSearchService() == null) {
                throw new GovernanceException("Term Search Service not Found");
            }
            Map<String, String> fields = new HashMap<>();
            if (mediaType != null) {
                fields.put(IndexingConstants.FIELD_MEDIA_TYPE, mediaType);
            }
            for (Map.Entry<String, List<String>> e : criteria.entrySet()) {
                StringBuilder builder = new StringBuilder();
                for (String referenceValue : e.getValue()) {
                    if (referenceValue != null && !"".equals(referenceValue)) {
                        String referenceValueModified = referenceValue.replace(" ", "\\ ");
                        referenceValueModified = referenceValueModified.toLowerCase();
                        if (referenceValueModified.contains("*\\ ")) {
                            referenceValueModified = referenceValueModified.replace("*\\ ", "* ");
                        }
                        if (referenceValueModified.contains("\\ *")) {
                            referenceValueModified = referenceValueModified.replace("\\ *", " *");
                        }
                        referenceValueModified = referenceValueModified.replaceAll("\\sand\\s", " && ");
                        builder.append(referenceValueModified).append(',');
                    }
                }
                if (builder.length() > 0) {
                    fields.put(e.getKey(), builder.substring(0, builder.length() - 1));
                }
            }
            //set whether authorization is required for the facet search.
            fields.put(IndexingConstants.AUTH_REQUIRED, String.valueOf(authRequired));

            //setting the facet Field which needs grouping. Facet Field is required for searching.
            if (facetField != null) {
                fields.put(IndexingConstants.FACET_FIELD_NAME, facetField);
            } else {
                throw new GovernanceException("Facet field is required. field cannot be null");
            }

            try {
                TermData[] termData = getTermsSearchService().search(fields);
                return Arrays.asList(termData);
            } catch (RegistryException e) {
                throw new GovernanceException("Unable to get terms for the given field", e);
            }
        }

        /**
         * Find all possible terms and its count for the given facet field and query criteria
         * @param criteria the filter criteria to be matched
         * @param facetField field used for faceting : required
         * @param mediaType artifact type need to filter : optional
         * @return term results
         * @throws GovernanceException
         */
        public static List<TermData> getTermDataList(String criteria, String facetField, String mediaType, Registry registry) throws GovernanceException {
            if (getTermsSearchService() == null) {
                throw new GovernanceException("Term Search Service not Found");
            }
            Map<String, String> fields = new HashMap<>();
            Map<String, String> possibleProperties = new HashMap<>();
            //maintain search query to support OR via content search
            String editedCriteria = buildSearchCriteria(criteria, registry, mediaType, possibleProperties, fields, false);

            if (editedCriteria != null && (editedCriteria.contains(FIELDS_OR_WILD_SEARCH) || editedCriteria.contains(FIELDS_OR_SEARCH))) {
                if (getTermsQuerySearchService() == null) {
                    throw new GovernanceException("Term Query Search Service not Found");
                }
                editedCriteria = editedCriteria.replace(FIELDS_OR_WILD_SEARCH, REPLACEMENT_OR_WILD_SEARCH);
                editedCriteria = editedCriteria.replace(FIELDS_AND_WILD_SEARCH, REPLACEMENT_AND_WILD_SEARCH);
                editedCriteria = editedCriteria.replace(FIELDS_OR_SEARCH, REPLACEMENT_OR_SEARCH);
                editedCriteria = editedCriteria.replace(FIELDS_AND_SEARCH, REPLACEMENT_AND_SEARCH);
                editedCriteria = editedCriteria.replace(SYMBOL_AND, REPLACEMENT_SYMBOL_AND);
                editedCriteria = editedCriteria.replace(SYMBOL_EQUAL, SYMBOL_COLON);
                editedCriteria = "(" + editedCriteria + ") AND mediaType:" + mediaType;
                log.debug("Content OR search | Search Criteria::: " + editedCriteria);
                try {
                    TermData[] termData = getTermsQuerySearchService().search(editedCriteria, facetField);
                    return Arrays.asList(termData);
                } catch (RegistryException e) {
                    throw new GovernanceException("Unable to get terms for the given field", e);
                }
            }

            //setting the facet Field which needs grouping. Facet Field is required for searching.
            if (facetField != null) {
                fields.put(IndexingConstants.FACET_FIELD_NAME, facetField);
            } else {
                throw new GovernanceException("Facet field is required. field cannot be null");
            }

            try {
                TermData[] termData = getTermsSearchService().search(fields);
                // Following check is done since Attribute Search service only has a way to search one property at a time
                if(possibleProperties.size() == 1) {

                    for (Map.Entry<String, String> entry : possibleProperties.entrySet()) {
                        String propertyName = entry.getKey();
                        fields.remove("overview_" + propertyName);
                        fields.put("propertyName", propertyName);
                        fields.put("rightPropertyValue", entry.getValue());
                        fields.put("rightOp", "eq");
                    }

                    TermData[] propertytermData = getTermsSearchService().search(fields);

                    Set<TermData> removeDuplicate = new TreeSet<>(new Comparator<TermData>() {
                        public int compare(TermData term1, TermData term2) {
                            return term1.getTerm().compareTo(term2.getTerm());
                        }
                    });
                    removeDuplicate.addAll(Arrays.asList(termData));
                    removeDuplicate.addAll(Arrays.asList(propertytermData));

                    List<TermData> mergeListWithoutDuplicates = new ArrayList<>();
                    mergeListWithoutDuplicates.addAll(removeDuplicate);

                    return mergeListWithoutDuplicates;
                }
                return Arrays.asList(termData);

            } catch (RegistryException e) {
                throw new GovernanceException("Unable to get terms for the given field", e);
            }
        }

         /**
         * Method used to retrieve cache object for RXT Configs.
         *
         * @param name the name of the cache
         * @return the cache object for the given cache manger and cache name
         */
        public static Cache<String, Boolean> getRXTConfigCache(String name) {
            CacheManager manager = getCacheManager();

            Cache<String, Boolean> cache = (manager != null) ? manager.<String, Boolean>getCache(name) :
                    Caching.getCacheManager().<String, Boolean>getCache(name);

            if (rxtCacheInitiated) {
                cache.registerCacheEntryListener(entryCreatedListener);
                cache.registerCacheEntryListener(entryUpdatedListener);
                cache.registerCacheEntryListener(entryRemovedListener);
                rxtCacheInitiated = true;
            }

            return cache;
        }

        /**
         * Get the Cache Manager for Registry
         *
         * @return CacheManager is returned
         */
        private static CacheManager getCacheManager() {
            return Caching.getCacheManagerFactory().getCacheManager(
                    RegistryConstants.REGISTRY_CACHE_MANAGER);
        }

        /*
         * This method is used to retrieve departments attached to a given artifact. Applicable to
         * ProjectGroup and Person artifacts
         *
         * @param registry - Registry associated with <code>artifact</code>
         * @param artifact - ProjectGroup or Person artifact to which Departments are attached
         * @return Department artifacts attached to <code>artifact</code>
         * @throws GovernanceException If operation fails
         */
       /* public static Department[] getAffiliatedDepartments(Registry registry, PeopleArtifact artifact)
                                            throws GovernanceException {
            List<Department> list = new ArrayList<Department>();
            PeopleManager manager = new PeopleManager(registry);
            String[] affiliations = artifact.getAttributes(GovernanceConstants.AFFILIATIONS_ATTRIBUTE);

            if (affiliations != null) {
                for (String deptText : affiliations) {
                    String deptName = deptText.split(GovernanceConstants.ENTRY_VALUE_SEPARATOR)[1];
                    *//* We are assuming data consistency at this point and hence, not checking the 0th
                       element of the above returned array *//*
                    PeopleArtifact pa = manager.getPeopleArtifactByName(deptName);
                    if (pa instanceof Department) {
                        list.add((Department) pa);
                    }
                }
            }
            return list.toArray(new Department[list.size()]);
        }*/

        /*
         * This method is used to retrieve organizations attached to a given artifact. Applicable to
         * ProjectGroup and Person artifacts
         *
         * @param registry - Registry associated with <code>artifact</code>
         * @param artifact - ProjectGroup or Person artifact to which Organizations are attached
         * @return Organization artifacts attached to <code>artifact</code>
         * @throws GovernanceException If operation fails
         */
        /*public static Organization[] getAffiliatedOrganizations(Registry registry,
                                                                PeopleArtifact artifact)
                                            throws GovernanceException {
            List<Organization> list = new ArrayList<Organization>();
            PeopleManager manager = new PeopleManager(registry);

            String[] affiliations = artifact.getAttributes(GovernanceConstants.AFFILIATIONS_ATTRIBUTE);
            if (affiliations != null) {
                for (String orgText : affiliations) {
                    String orgName = orgText.split(GovernanceConstants.ENTRY_VALUE_SEPARATOR)[1];
                    *//* We are assuming data consistency at this point and hence, not checking the 0th
                       element of the above returned array *//*
                    PeopleArtifact pa = manager.getPeopleArtifactByName(orgName);
                    if (pa instanceof Organization) {
                        list.add((Organization) pa);
                    }
                }
            }
            return list.toArray(new Organization[list.size()]);
        }*/

        /*
         * This method is used to retrieve project groups attached to a given artifact. Applicable to
         * Person artifacts
         *
         * @param registry - Registry associated with <code>artifact</code>
         * @param artifact - Person artifact to which project groups are attached
         * @return ProjectGroup artifacts attached to <code>artifact</code>
         * @throws GovernanceException If operation fails
         */
        /*public static ProjectGroup[] getAffiliatedProjectGroups(Registry registry,
                                                                PeopleArtifact artifact)
                                            throws GovernanceException {
            List<ProjectGroup> list = new ArrayList<ProjectGroup>();
            PeopleManager manager = new PeopleManager(registry);
            String[] affiliations = artifact.getAttributes(GovernanceConstants.AFFILIATIONS_ATTRIBUTE);
            if (affiliations != null) {
                for (String pgText : affiliations) {
                    String pgName = pgText.split(GovernanceConstants.ENTRY_VALUE_SEPARATOR)[1];
                    *//* We are assuming data consistency at this point and hence, not checking the 0th
              element of the above returned array *//*
                    PeopleArtifact pa = manager.getPeopleArtifactByName(pgName);
                    if (pa instanceof ProjectGroup) {
                        list.add((ProjectGroup) pa);
                    }
                }
            }
            return list.toArray(new ProjectGroup[list.size()]);
        }*/

        /*
         * This method is used to retrieve project groups that have the given artifact (Organization or
         * Department) as an affiliation
         *
         * @param registry - Registry associated with <code>artifact</code>
         * @param artifact - Organization/Department artifact
         * @return ProjectGroups that have <code>artifact</code> as an affiliation
         * @throws GovernanceException
         */
    /*
        public static ProjectGroup[] getAttachedProjectGroups(Registry registry, PeopleArtifact artifact)
                                                   throws GovernanceException {
            ProjectGroup[] pgs = new PeopleManager(registry).getAllProjectGroups();
            List<ProjectGroup> list = new ArrayList<ProjectGroup>();
            for (ProjectGroup pg : pgs) {
                for (Department department : pg.getDepartments()) {
                    if (artifact.getName().equals(department.getName())) {
                        list.add(pg);
                    }
                }
            }
            return list.toArray(new ProjectGroup[list.size()]);
        }
    */

        /*
         * This method is used to retrieve persons that have the given artifact (Organization or
         * Department) as an affiliation
         *
         * @param registry - Registry associated with <code>artifact</code>
         * @param artifact - Organization/Department artifact
         * @return Person artifacts that have <code>artifact</code> as an affiliation
         * @throws GovernanceException
         */
    /*
        public static Person[] getAttachedPersons(Registry registry, PeopleArtifact artifact)
                                          throws GovernanceException {
            Person[] persons = new PeopleManager(registry).getAllPersons();
            List<Person> list = new ArrayList<Person>();
            for (Person person : persons) {
                for (Department department : person.getDepartments()) {
                    if (artifact.getName().equals(department.getName())) {
                        list.add(person);
                    }
                }
            }
            return list.toArray(new Person[list.size()]);
        }
    */

        /*
         * This method writes sub-group associations contained within the given ProjectGroup to the
         * registry. Existence of all the sub groups must be validated before calling this method.
         *
         * @param registry
         * @param projectGroup
         * @throws GovernanceException
         */
    /*
        public static void writeSubGroupAssociations(Registry registry, ProjectGroup projectGroup)
                                              throws GovernanceException {
            try {
                if (!registry.resourceExists(projectGroup.getPath())) {
                    return;
                }
                ProjectGroup[] subGroups = projectGroup.getSubGroups();
                // Get the existing association list which is related to the current operation
                Set<String> existingSet = new HashSet<String>();
                for (Association asso : registry.getAllAssociations(projectGroup.getPath())) {
                    if ((GovernanceConstants.SUB_GROUP.equals(asso.getAssociationType()) &&
                            asso.getSourcePath().equals(projectGroup.getPath()))
                            ||
                            (GovernanceConstants.IS_PART_OF.equals(asso.getAssociationType()) &&
                                    asso.getDestinationPath().equals(projectGroup.getPath()))) {
                        existingSet.add(asso.getSourcePath() + SEPARATOR + asso.getDestinationPath() +
                                SEPARATOR + asso.getAssociationType());
                    }
                }

                // Get the updated association list from the projectGroup object
                Set<String> updatedSet = new HashSet<String>();
                for (ProjectGroup subGroup : subGroups) {
                    updatedSet.add(projectGroup.getPath() + SEPARATOR + subGroup.getPath() +
                            SEPARATOR + GovernanceConstants.SUB_GROUP);
                    updatedSet.add(subGroup.getPath() + SEPARATOR + projectGroup.getPath() + SEPARATOR +
                            GovernanceConstants.IS_PART_OF);
                }
                updateAssociations(registry, existingSet, updatedSet);
            } catch (RegistryException e) {
                String msg = "Error in writing sub group associations, parent project-group id: " +
                        projectGroup.getId() + ", path: " + projectGroup.getPath();
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }
    */

        /*
         * This method writes owner associations contained within the service object to the registry.
         * Existence of all the owners as people artifacts must be validated before calling this method.
         *
         * @param registry
         * @param service
         * @throws GovernanceException
         */
    /*
        public static void writeOwnerAssociations(Registry registry, Service service)
                                           throws GovernanceException {
            try {
                if (!registry.resourceExists(service.getPath())) {
                    return;
                }
                PeopleArtifact[] owners = service.getOwners();
                // Remove associations that are not there anymore and add any new associations
                Association[] oldAssociations = registry.getAllAssociations(service.getPath());
                Set<String> oldSet = new HashSet<String>();
                for (Association association : oldAssociations) {
                    if (GovernanceConstants.OWNED_BY.equals(association.getAssociationType()) ||
                            GovernanceConstants.OWNS.equals(association.getAssociationType())) {
                        oldSet.add(association.getSourcePath() + SEPARATOR +
                                association.getDestinationPath() + SEPARATOR +
                                association.getAssociationType());
                    }
                }
                Set<String> updatedSet = new HashSet<String>();
                for (PeopleArtifact owner : owners) {
                    updatedSet.add(service.getPath() + SEPARATOR + owner.getPath() + SEPARATOR +
                            GovernanceConstants.OWNED_BY);
                    updatedSet.add(owner.getPath() + SEPARATOR + service.getPath() + SEPARATOR +
                            GovernanceConstants.OWNS);
                }
                updateAssociations(registry, oldSet, updatedSet);
            } catch (RegistryException e) {
                String msg = "Error in associating owners to service. Id: " + service.getId() +
                        ", path: " + service.getPath();
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }
    */

        /*
         * This method writes consumer associations contained within the service object to the registry.
         * Existence of all the consumers as people artifacts must be validated before calling this
         * method.
         *
         * @param registry
         * @param service
         * @throws GovernanceException
         */
    /*
        public static void writeConsumerAssociations(Registry registry, Service service)
                                             throws GovernanceException {
            try {
                if (!registry.resourceExists(service.getPath())) {
                    return;
                }
                PeopleArtifact[] consumers = service.getConsumers();
                // Remove associations that are not there anymore and add any new associations
                Association[] oldAssociations = registry.getAllAssociations(service.getPath());
                Set<String> oldSet = new HashSet<String>();
                for (Association association : oldAssociations) {
                    if (GovernanceConstants.CONSUMED_BY.equals(association.getAssociationType()) ||
                            GovernanceConstants.CONSUMES.equals(association.getAssociationType())) {
                        oldSet.add(association.getSourcePath() + SEPARATOR +
                                association.getDestinationPath() + SEPARATOR +
                                association.getAssociationType());
                    }
                }
                Set<String> updatedSet = new HashSet<String>();
                for (PeopleArtifact consumer : consumers) {
                    updatedSet.add(service.getPath() + SEPARATOR + consumer.getPath() + SEPARATOR +
                            GovernanceConstants.CONSUMED_BY);
                    updatedSet.add(consumer.getPath() + SEPARATOR + service.getPath() + SEPARATOR +
                            GovernanceConstants.CONSUMES);
                }
                updateAssociations(registry, oldSet, updatedSet);
            } catch (RegistryException e) {
                String msg = "Error in associating owners to service. Id: " + service.getId() +
                        ", path: " + service.getPath();
                log.error(msg, e);
                throw new GovernanceException(msg, e);
            }
        }
    */

        /*
         * This method extracts people names from the given attribute of the given artifact and returns
         * an array containing PeopleArtifacts represented by those names.
         * Existence of people artifacts listed under the atrribute name must be validated before
         * calling this method.
         *
         * @param registry      Associated registry
         * @param artifact      GovernanceArtifact which stores people list as an attribute
         * @param attributeName Name of the attribute which stores people names
         * @throws GovernanceException
         */
    /*
        public static PeopleArtifact[] extractPeopleFromAttribute(Registry registry,
                                                                  GovernanceArtifact artifact,
                                                                  String attributeName)
                                                    throws GovernanceException {
            String[] peopleTexts = artifact.getAttributes(attributeName);
            PeopleManager manager = new PeopleManager(registry);
            List<PeopleArtifact> list = new ArrayList<PeopleArtifact>();
            if (peopleTexts != null) {
                for (String peopleText : peopleTexts) {
                    String name = peopleText.split(GovernanceConstants.ENTRY_VALUE_SEPARATOR)[1];
                    PeopleArtifact pa = manager.getPeopleArtifactByName(name);
                    if (pa == null) {
                        String msg = "Invalid people artifact name is found within the governance " +
                                "artifact. Path: " + artifact.getPath() + ", Invalid people artifact " +
                                "name:" + name;
                        log.error(msg);
                        throw new GovernanceException(msg);
                    } else {
                        list.add(pa);
                    }
                }
            }
            return list.toArray(new PeopleArtifact[list.size()]);
        }
    */

    /*
        private static void updateAssociations(Registry registry, Set<String> existingAssociationSet,
                                               Set<String> updatedAssociationSet)
                                        throws RegistryException {
            Set<String> removedAssociations = new HashSet<String>(existingAssociationSet);
            removedAssociations.removeAll(updatedAssociationSet);

            Set<String> newAssociations = new HashSet<String>(updatedAssociationSet);
            newAssociations.removeAll(existingAssociationSet);

            for (String removedAssociation : removedAssociations) {
                String[] params = removedAssociation.split(SEPARATOR);
                try {
                    for (int i = 0; i < 2; i++) {
                        if (GovernanceUtils.retrieveGovernanceArtifactByPath(registry, params[i])
                                instanceof PeopleArtifact) {
                            registry.removeAssociation(params[0], params[1], params[2]);
                            break;
                        }
                    }
                } catch (GovernanceException ignored) {
                }
            }

            for (String newAssociation : newAssociations) {
                String[] params = newAssociation.split(SEPARATOR);
                registry.addAssociation(params[0], params[1], params[2]);
            }
        }
    */

        public static void removeArtifactFromPath(Registry registry, String path)
                throws GovernanceException {
            try {
                if (registry.resourceExists(path)) {
                    deleteLifecycleHistoryFile(path, registry);
                    registry.delete(path);
                }
                ArtifactCache artifactCache =
                        ArtifactCacheManager.getCacheManager().getTenantArtifactCache(((UserRegistry) registry).getTenantId());
                if (artifactCache != null && path != null && artifactCache.getArtifact(path) != null) {
                    artifactCache.invalidateArtifact(path);
                }
            } catch (RegistryException e) {
                String msg = "Error in deleting the the artifact path:" + path + ".";
                throw new GovernanceException(msg, e);
            }
        }

        public static List<String> getUniqueAttributesNames(Registry registry,
                                                            String mediaType) throws GovernanceException {
            try {
                GovernanceArtifactConfiguration configuration = findGovernanceArtifactConfigurationByMediaType(mediaType, registry);
                if (configuration != null) {
                    return configuration.getUniqueAttributes();
                }
            } catch (RegistryException e) {
                throw new GovernanceException(e);
            }
            return null;
        }

        /**
         * Validates a given artifact to ensure all the mandatory fields are filled
         * If a mandatory field is left empty this check method will throw an exception
         * indicating field name to be filled.
         *
         * @param registry              the instance of the registry.
         * @param elementString         the short name of the artifact type.
         * @param artifact              artifact to be checked for mandatory fields.
         * @throws GovernanceException
         */
        public static void CheckMandatoryFields(Registry registry, String elementString, GovernanceArtifact artifact)
                throws GovernanceException {
            if (artifact instanceof WsdlImpl || artifact instanceof SchemaImpl || artifact instanceof PolicyImpl) {
                return;
            }

            GovernanceArtifactConfiguration configuration = null;
            try {
                configuration = GovernanceUtils.findGovernanceArtifactConfiguration(elementString, registry);
            } catch (RegistryException e) {
                throw new GovernanceException("Retrieving RXT configuration for type :" + elementString + "failed.", e);
            }

            if (configuration == null) {
                throw new GovernanceException("Could not find RXT configuration for type :" + elementString);
            }

            List<Map> mandatoryAttributes = configuration.getMandatoryAttributes();

            if (mandatoryAttributes == null) {
                return;
            }
            Map<String, Object> map;
            for (int i = 0; i < mandatoryAttributes.size(); ++i) {
                map = mandatoryAttributes.get(i);
                String prop = (String) map.get("properties");
                List<String> keys = (List<String>) map.get("keys");

                if (prop != null && "unbounded".equals(prop)) {
                    //assume there are only 1 key
                    String[] values = artifact.getAttributes((String) keys.get(0));
                    if (values != null) {
                        for (int j = 0; j < values.length; ++j) {
                            if (values[j] == null || "".equals(values[j])) {
                                //return an exception to stop adding artifact
                                throw new GovernanceException((String) map.get("name") + " is a required field, " +
                                                              "Please provide a value for this parameter.");
                            }
                        }
                    }
                } else {
                    String value = "";
                    for (int j = 0; j < keys.size(); ++j) {
                        String v = artifact.getAttribute(keys.get(j));
                        if (j != 0) {
                            value += ":";
                        }
                        value += (v == null ? "" : v);
                    }
                    if (value == null || "".equals(value)) {
                        //return an exception to stop adding artifact
                        throw new GovernanceException((String) map.get("name") + " is a required field, " +
                                                      "Please provide a value for this parameter.");
                    }
                }
            }
        }

        /**
         * This method deletes the lifecycle history file of a given artifact
         * @param artifactPath The resource path relative to governance registry
         * @param registry governace registry instance
         * @throws GovernanceException
         */
        private static void deleteLifecycleHistoryFile(String artifactPath, Registry registry) throws GovernanceException {
            String artifactRootPath = RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH + artifactPath;
            String historyResourcePath = GovernanceConstants.LIFECYCLE_HISTORY_PATH
                                         + artifactRootPath.replaceAll("/", "_");
            try {
                Registry govRegistry;
                if (registryService != null){
                    int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
                    govRegistry = registryService.getGovernanceSystemRegistry(tenantId);
                } else {
                    //This will be used, when executing unit test cases.
                    govRegistry =  registry;
                }
                if (govRegistry.resourceExists(historyResourcePath)) {
                    govRegistry.delete(historyResourcePath);
                }
            } catch (RegistryException e) {
                String msg = "Error in deleting the the lifecycle history file at: " + historyResourcePath + ".";
                throw new GovernanceException(msg, e);
            }
        }
    }