com.jaspersoft.jasperserver.api.metadata.tenant.service.impl.TenantServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.jasperserver.api.metadata.tenant.service.impl.TenantServiceImpl.java

Source

/*
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package com.jaspersoft.jasperserver.api.metadata.tenant.service.impl;

import com.jaspersoft.jasperserver.api.JSException;
import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.logging.diagnostic.domain.DiagnosticAttribute;
import com.jaspersoft.jasperserver.api.logging.diagnostic.helper.DiagnosticAttributeBuilder;
import com.jaspersoft.jasperserver.api.logging.diagnostic.service.Diagnostic;
import com.jaspersoft.jasperserver.api.logging.diagnostic.service.DiagnosticCallback;
import com.jaspersoft.jasperserver.api.metadata.common.service.ResourceFactory;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.HibernateDaoImpl;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.util.IlikeEscapeAwareExpression;
import com.jaspersoft.jasperserver.api.metadata.common.util.DatabaseCharactersEscapeResolver;
import com.jaspersoft.jasperserver.api.metadata.tenant.service.TenantPersistenceResolver;
import com.jaspersoft.jasperserver.api.metadata.user.domain.Role;
import com.jaspersoft.jasperserver.api.metadata.user.domain.Tenant;
import com.jaspersoft.jasperserver.api.metadata.user.domain.User;
import com.jaspersoft.jasperserver.api.metadata.user.domain.impl.hibernate.RepoTenant;
import com.jaspersoft.jasperserver.api.metadata.user.service.TenantService;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.CacheMode;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Tenant service implementation.
 *
 * @author achan
 */
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class TenantServiceImpl extends HibernateDaoImpl
        implements TenantService, TenantPersistenceResolver, Diagnostic {

    Pattern patternTenantByURI = Pattern.compile("^(?:/" + TenantService.ORGANIZATIONS + "/([^/]+))*/?.*");

    protected static final Log log = LogFactory.getLog(TenantServiceImpl.class);
    private ResourceFactory objectMappingFactory;
    private ResourceFactory persistentClassFactory;
    private String userOrgIdDelimiter;
    private DatabaseCharactersEscapeResolver databaseCharactersEscapeResolver;
    private boolean isTenantCaseSensitive;

    public void setDatabaseCharactersEscapeResolver(
            DatabaseCharactersEscapeResolver databaseCharactersEscapeResolver) {
        this.databaseCharactersEscapeResolver = databaseCharactersEscapeResolver;
    }

    public ResourceFactory getPersistentClassFactory() {
        return persistentClassFactory;
    }

    public void setPersistentClassFactory(ResourceFactory persistentClassFactory) {
        this.persistentClassFactory = persistentClassFactory;
    }

    public ResourceFactory getObjectMappingFactory() {
        return objectMappingFactory;
    }

    public void setObjectMappingFactory(ResourceFactory objectFactory) {
        this.objectMappingFactory = objectFactory;
    }

    public boolean isTenantCaseSensitive() {
        return isTenantCaseSensitive;
    }

    public void setTenantCaseSensitive(boolean tenantCaseSensitive) {
        isTenantCaseSensitive = tenantCaseSensitive;
    }

    protected RepoTenant getRepoTenant(String tenantId, boolean required) {
        // Search with sensitivity according to the configuration.
        List tenantList = getHibernateTemplate()
                .findByCriteria(createTenantSearchCriteria(tenantId, isTenantCaseSensitive));

        // Before 5.0.1 we had case sensitive tenant ID. But there was a bug 24226 opened with at least 4 customer
        // cases that tenant ID should be case insensitive. Because of previous case sensitive logic existing customers
        // could have several tenants which tenant ID is the same when case insensitive logic is applied but different
        // when case sensitive logic is applied. So, we decided to implement adaptive logic which will allow both worlds
        // live together.
        // It means that by default we are trying to find the tenant using case insensitive logic (this is the matter of
        // configuration). If more then 1 tenant was found we do one more search with case sensitive logic applied.
        if (tenantList.size() > 1) {
            log.warn(tenantList.size() + " tenants were found during case insensitive search for \"" + tenantId
                    + "\". Retrying case sensitive search.");

            // Case sensitive search.
            tenantList = getHibernateTemplate().findByCriteria(createTenantSearchCriteria(tenantId, true));
        }

        return extractTenant(tenantId, required, tenantList);
    }

    private RepoTenant extractTenant(String tenantId, boolean required, List tenantList) {
        RepoTenant tenant = null;

        if (tenantList.isEmpty()) {
            if (required) {
                throw new JSException("Tenant not found with Tenant ID \"" + tenantId + "\"");//TODO i18n
            }

            log.debug("Tenant not found with Tenant ID \"" + tenantId + "\".");
        } else if (tenantList.size() == 1) {
            tenant = (RepoTenant) tenantList.get(0);
        }

        return tenant;
    }

    private DetachedCriteria createTenantSearchCriteria(String tenantId, boolean isCaseSensitive) {
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());

        criteria.add(
                isCaseSensitive ? Restrictions.eq("tenantId", tenantId) : Restrictions.ilike("tenantId", tenantId));
        criteria.getExecutableCriteria(getSession()).setCacheable(true);

        return criteria;
    }

    protected RepoTenant getRepoTenantByAlias(String tenantAlias, boolean required) {
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());
        criteria.add(Restrictions.eq("tenantAlias", tenantAlias));
        criteria.getExecutableCriteria(getSession()).setCacheable(true);
        List tenantList = getHibernateTemplate().findByCriteria(criteria);
        RepoTenant tenant;
        if (tenantList.isEmpty()) {
            if (required) {
                throw new JSException("Tenant not found with Tenant Alias \"" + tenantAlias + "\"");//TODO i18n
            }

            log.debug("Tenant not found with Tenant Alias \"" + tenantAlias + "\"");
            tenant = null;
        } else {
            tenant = (RepoTenant) tenantList.get(0);
        }
        return tenant;
    }

    protected Class persistentTenantClass() {
        return getPersistentClassFactory().getImplementationClass(Tenant.class);
    }

    protected RepoTenant getRepoTenantBasedOnTenantUri(ExecutionContext context, String tenantUri) {
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());
        criteria.add(Restrictions.eq("tenantUri", tenantUri));
        criteria.getExecutableCriteria(getSession()).setCacheable(true);
        List tenantList = getHibernateTemplate().findByCriteria(criteria);
        RepoTenant tenant = null;
        if (tenantList.isEmpty()) {
            log.debug("Tenant not found with Tenant Name \"" + tenantUri + "\"");
        } else {
            tenant = (RepoTenant) tenantList.get(0);
        }
        return tenant;
    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.user.service.UserAuthorityService#putUser(com.jaspersoft.jasperserver.api.common.domain.ExecutionContext, com.jaspersoft.jasperserver.api.metadata.user.domain.User)
     */
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void putTenant(ExecutionContext context, Tenant aTenant) {
        RepoTenant existingTenant = getRepoTenant(aTenant.getId(), false);
        if (existingTenant == null) {
            existingTenant = (RepoTenant) getPersistentClassFactory().newObject(Tenant.class);
        }
        existingTenant.copyFromClient(aTenant, this);
        getHibernateTemplate().saveOrUpdate(existingTenant);
    }

    protected List getRepoSubTenants(ExecutionContext context, String parentTenantId) {
        RepoTenant parent = getRepoTenant(parentTenantId, false);
        if (parent == null || parent.getSubTenants() == null) {
            return new ArrayList(0);
        }
        return new ArrayList(parent.getSubTenants());
    }

    public List getSubTenantList(ExecutionContext context, Tenant parentTenant) {
        List persistentTenants = getRepoSubTenants(context, parentTenant.getId());
        return toClientTenantList(persistentTenants);
    }

    public List getSubTenantList(ExecutionContext context, String parnentTenantId) {
        List persistentTenants = getRepoSubTenants(context, parnentTenantId);
        return toClientTenantList(persistentTenants);
    }

    protected List<Tenant> toClientTenantList(List persistentTenants) {
        if (persistentTenants == null) {
            return null;
        }

        List<Tenant> tenants = new ArrayList<Tenant>(persistentTenants.size());
        for (Object persistentTenant1 : persistentTenants) {
            RepoTenant persistentTenant = (RepoTenant) persistentTenant1;
            Tenant tenant = toClientTenant(persistentTenant);
            tenants.add(tenant);
        }
        return tenants;
    }

    public Tenant getTenant(ExecutionContext context, String tenantId) {
        RepoTenant rTenant = getRepoTenant(tenantId, false);
        if (rTenant == null) {
            return null;
        }
        return toClientTenant(rTenant);
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void deleteTenant(ExecutionContext context, String tenantId) {
        RepoTenant tenant = getRepoTenant(tenantId, false);
        if (tenant != null) {
            getHibernateTemplate().delete(tenant);
            getHibernateTemplate().flush();
        } else {
            if (log.isInfoEnabled()) {
                log.info("Tenant " + tenantId + " not found for deletion");
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void updateTenant(ExecutionContext context, Tenant aTenant) {
        putTenant(context, aTenant);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public List getAllSubTenantList(ExecutionContext context, final String parentTenantId) {
        return getAllSubTenantList(context, parentTenantId, null);
    }

    @SuppressWarnings({ "unchecked" })
    @Transactional(propagation = Propagation.REQUIRED)
    public List<String> getAllSubTenantIdList(ExecutionContext context, final String parentTenantId) {
        List<String> subTenantIdList = new ArrayList<String>();

        /* Retrieving parent tenant. */
        RepoTenant parent = getRepoTenant(parentTenantId, false);

        if (parent != null) {
            DetachedCriteria criteria = createSubTenantsCriteria(parent, null, -1);
            criteria.getExecutableCriteria(getSession()).setCacheable(true);
            criteria.setProjection(Projections.property("tenantId"));
            subTenantIdList.addAll(getHibernateTemplate().findByCriteria(criteria));
        }

        return subTenantIdList;
    }

    private DetachedCriteria createSubTenantsCriteria(RepoTenant parentTenant, String text, int depth) {
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());
        String value = "/%";

        if ("/".equals(parentTenant.getTenantUri())) {
            /* Excluding root parent from sub list. */
            criteria.add(Restrictions.ne("tenantId", parentTenant.getTenantId()));
        } else {
            value = parentTenant.getTenantUri() + value;
        }

        criteria.add(Restrictions.like("tenantUri", value));

        if (depth > 0) {
            StringBuilder boundary = new StringBuilder(value);
            for (; depth > 0; depth--) {
                boundary.append("/%");
            }
            criteria.add(Restrictions.not(Restrictions.like("tenantUri", boundary.toString())));
        }

        if (text != null) {
            text = databaseCharactersEscapeResolver.getEscapedText(text.trim());
            if (text.length() > 0) {
                Disjunction disjunction = Restrictions.disjunction();

                disjunction.add(new IlikeEscapeAwareExpression("tenantId", text, MatchMode.ANYWHERE));
                disjunction.add(new IlikeEscapeAwareExpression("tenantAlias", text, MatchMode.ANYWHERE));
                disjunction.add(new IlikeEscapeAwareExpression("tenantName", text, MatchMode.ANYWHERE));
                disjunction.add(new IlikeEscapeAwareExpression("tenantDesc", text, MatchMode.ANYWHERE));

                criteria.add(disjunction);
            }
        }
        return criteria;
    }

    private void getAllSubTenantListPrivate(String parentTenantId, ArrayList allSubTenants) {
        List subTenant = getSubTenantList(null, parentTenantId);
        for (int i = 0; i < subTenant.size(); i++) {
            allSubTenants.add(subTenant.get(i));
            getAllSubTenantListPrivate(((Tenant) subTenant.get(i)).getId(), allSubTenants);
        }
    }

    public int getNumberOfTenants(ExecutionContext context) {
        List allTenants = getAllSubTenantList(null, ORGANIZATIONS);
        return allTenants.size();
    }

    public Tenant getDefaultTenant(ExecutionContext context) {
        List allTenants = getAllSubTenantList(null, ORGANIZATIONS);
        if (allTenants.size() == 1) {
            return (Tenant) allTenants.get(0);
        } else {
            return null;
        }
    }

    public Tenant getTenantBasedOnTenantUri(ExecutionContext context, String tenantUri) {
        RepoTenant rTenant = getRepoTenantBasedOnTenantUri(context, tenantUri);
        if (rTenant == null) {
            return null;
        }
        Tenant tenant = toClientTenant(rTenant);
        return tenant;
    }

    protected Tenant toClientTenant(RepoTenant rTenant) {
        Tenant tenant = (Tenant) objectMappingFactory.newObject(Tenant.class);
        rTenant.copyToClient(tenant);
        return tenant;
    }

    public String getUserOrgIdDelimiter() {
        return userOrgIdDelimiter;
    }

    public void setUserOrgIdDelimiter(String userOrgIdDelimiter) {
        this.userOrgIdDelimiter = userOrgIdDelimiter;
    }

    public String getTenantIdBasedOnRepositoryUri(ExecutionContext context, String uri) {
        Matcher matcher = patternTenantByURI.matcher(uri);
        String possibleId = null;
        if (matcher.matches()) {
            possibleId = matcher.group(1);
            if (TenantService.ORG_TEMPLATE.equals(possibleId)) {
                possibleId = getTenantIdBasedOnRepositoryUri(context,
                        uri.substring(0, uri.lastIndexOf(TenantService.ORGANIZATIONS)));
            }
        }
        return possibleId;
    }

    public Tenant getTenantBasedOnRepositoryUri(ExecutionContext context, String uri) {
        String tenantId = getTenantIdBasedOnRepositoryUri(context, uri);
        if (tenantId != null) {
            return getTenant(context, tenantId);
        }
        return null;
    }

    public boolean isMultiTenantEnvironment(ExecutionContext context) {
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());
        criteria.add(Restrictions.ne("tenantUri", "/"));
        criteria.getExecutableCriteria(getSession()).setCacheable(true);
        List tenantList = getHibernateTemplate().findByCriteria(criteria);
        return tenantList.size() > 1;
    }

    public RepoTenant getPersistentTenant(String tenantId, boolean required) {
        if (tenantId == null || tenantId.length() == 0) {
            return null;
        }

        return getRepoTenant(tenantId, required);
    }

    public RepoTenant getPersistentTenantByAlias(String tenantAlias, boolean required) {
        if (tenantAlias == null || tenantAlias.length() == 0) {
            return null;
        }

        return getRepoTenantByAlias(tenantAlias, required);
    }

    public String getUniqueTenantId(String proposedTenantId) {
        List similarTenantIdList;
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());
        criteria.add(Restrictions.like("tenantId", proposedTenantId + "%").ignoreCase());
        criteria.getExecutableCriteria(getSession()).setCacheable(true);
        List tenantList = getHibernateTemplate().findByCriteria(criteria);
        if (tenantList.isEmpty()) {
            similarTenantIdList = Collections.emptyList();
        } else {
            similarTenantIdList = new ArrayList(tenantList.size());
            for (int i = 0; i < tenantList.size(); i++) {
                similarTenantIdList.add(((RepoTenant) tenantList.get(i)).getTenantId());
            }
        }

        return getUniqueItem(proposedTenantId, similarTenantIdList);
    }

    private String getUniqueItem(String proposedItem, List similarItemsList) {
        if (similarItemsList.size() == 0) {
            return proposedItem;
        }

        for (int i = 0; i < similarItemsList.size(); i++) {
            String orgId = (String) similarItemsList.get(i);
            if (orgId.equalsIgnoreCase(proposedItem)) {
                break;
            }
            if (i == (similarItemsList.size() - 1)) {
                return proposedItem;
            }
        }

        int index = 1;
        boolean ready = false;
        while (!ready) {
            for (int i = 0; i < similarItemsList.size(); i++) {
                String orgId = (String) similarItemsList.get(i);
                if ((proposedItem + index).equalsIgnoreCase(orgId)) {
                    index++;
                    break;
                }
                if (i == (similarItemsList.size() - 1)) {
                    ready = true;
                    proposedItem = proposedItem + index;
                }
            }
        }

        return proposedItem;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public String getUniqueTenantAlias(String proposedAlias) {
        List similarAliasesAndTenantIdList;
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());
        criteria.add(Restrictions.like("tenantAlias", proposedAlias + "%").ignoreCase());
        criteria.getExecutableCriteria(getSession()).setCacheable(true);
        List tenantAliasesList = getHibernateTemplate().findByCriteria(criteria);
        if (tenantAliasesList.isEmpty()) {
            similarAliasesAndTenantIdList = Collections.emptyList();
        } else {
            similarAliasesAndTenantIdList = new ArrayList(tenantAliasesList.size());
            for (int i = 0; i < tenantAliasesList.size(); i++) {
                similarAliasesAndTenantIdList.add(((RepoTenant) tenantAliasesList.get(i)).getTenantAlias());
            }
        }

        criteria = DetachedCriteria.forClass(persistentTenantClass());
        criteria.add(Restrictions.like("tenantId", proposedAlias + "%"));
        criteria.getExecutableCriteria(getSession()).setCacheable(true);
        List tenantIdsList = getHibernateTemplate().findByCriteria(criteria);
        if (!tenantIdsList.isEmpty()) {
            if (similarAliasesAndTenantIdList.isEmpty()) {
                similarAliasesAndTenantIdList = new ArrayList(tenantIdsList.size());
            }
            for (int i = 0; i < tenantIdsList.size(); i++) {
                similarAliasesAndTenantIdList.add(((RepoTenant) tenantIdsList.get(i)).getTenantId());
            }
        }

        // Alias should be unique among all tenant IDs and tenant aliases.
        return getUniqueItem(proposedAlias, similarAliasesAndTenantIdList);
    }

    public int getNumberOfUsers(ExecutionContext context, String tenantId) {
        return createNumberOfUsersOrRolesCriteria(tenantId,
                getPersistentClassFactory().getImplementationClass(User.class));
    }

    public int getNumberOfRoles(ExecutionContext context, String tenantId) {
        return createNumberOfUsersOrRolesCriteria(tenantId,
                getPersistentClassFactory().getImplementationClass(Role.class));
    }

    private int createNumberOfUsersOrRolesCriteria(String tenantId, Class aClass) {
        Integer rowCount = 0;

        RepoTenant tenant = getRepoTenant(tenantId, false);
        if (tenant != null) {
            DetachedCriteria criteria = DetachedCriteria.forClass(aClass);
            criteria.createAlias("tenant", "t");

            criteria.add(Restrictions.or(Restrictions.eq("t.tenantUri", tenant.getTenantUri()), Restrictions
                    .like("t.tenantUri", tenant.getTenantUri().equals("/") ? "/%" : tenant.getTenantUri() + "/%")));

            criteria.setProjection(Projections.count("id"));
            criteria.getExecutableCriteria(getSession()).setCacheable(true);

            List results = getHibernateTemplate().findByCriteria(criteria);
            if (results != null && !results.isEmpty()) {

                rowCount = (Integer) results.get(0);
            }
        }

        return rowCount;
    }

    public int getSubTenantsCount(ExecutionContext context, String parentTenantId, String text) {
        DetachedCriteria criteria = createSearchTenantsCriteria(parentTenantId, text);

        criteria.setProjection(Projections.rowCount());
        criteria.getExecutableCriteria(getSession()).setCacheable(true);

        List results = getHibernateTemplate().findByCriteria(criteria);

        if (results != null && !results.isEmpty()) {
            return (Integer) results.get(0);
        }

        return 0;
    }

    public List<Tenant> getSubTenants(ExecutionContext context, String parentTenantId, String text, int firstResult,
            int maxResults) {
        DetachedCriteria criteria = createSearchTenantsCriteria(parentTenantId, text);
        criteria.getExecutableCriteria(getSession()).setCacheable(true);

        List results = getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);

        return toClientTenantList(results);
    }

    private DetachedCriteria createSearchTenantsCriteria(String parentTenantId, String text) {
        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());

        criteria.createAlias("parent", "p");
        criteria.add(Restrictions.naturalId().set("p.tenantId", parentTenantId));

        if (text != null) {
            text = databaseCharactersEscapeResolver.getEscapedText(text.trim());
            if (text.length() > 0) {
                Disjunction disjunction = Restrictions.disjunction();

                //                disjunction.add(Restrictions.ilike("tenantId", "%" + text + "%"));
                //                disjunction.add(Restrictions.ilike("tenantAlias", "%" + text + "%"));
                //                disjunction.add(Restrictions.ilike("tenantName", "%" + text + "%"));
                //                disjunction.add(Restrictions.ilike("tenantDesc", "%" + text + "%"));

                disjunction.add(new IlikeEscapeAwareExpression("tenantId", text, MatchMode.ANYWHERE));
                disjunction.add(new IlikeEscapeAwareExpression("tenantAlias", text, MatchMode.ANYWHERE));
                disjunction.add(new IlikeEscapeAwareExpression("tenantName", text, MatchMode.ANYWHERE));
                disjunction.add(new IlikeEscapeAwareExpression("tenantDesc", text, MatchMode.ANYWHERE));

                criteria.add(disjunction);
            }
        }

        return criteria;
    }

    public Map<String, Integer> getSubTenantsCountMap(List<String> tenantIds) {
        if (tenantIds == null || tenantIds.size() == 0) {
            return Collections.emptyMap();
        }

        DetachedCriteria criteria = DetachedCriteria.forClass(persistentTenantClass());

        criteria.createAlias("parent", "p");
        criteria.add(Restrictions.in("p.tenantId", tenantIds));

        criteria.setProjection(Projections.projectionList().add(Projections.rowCount())
                .add(Projections.groupProperty("p.tenantId")));
        criteria.getExecutableCriteria(getSession()).setCacheable(true);

        List results = getHibernateTemplate().findByCriteria(criteria);

        Map<String, Integer> subTenantCounts = new HashMap<String, Integer>(tenantIds.size(), 1);
        if (results != null && results.size() > 0) {
            for (Object result : results) {
                String tenantId = (String) ((Object[]) result)[1];
                Integer count = (Integer) ((Object[]) result)[0];

                subTenantCounts.put(tenantId, count);
            }
        }

        for (String tenantId : tenantIds) {
            if (!subTenantCounts.containsKey(tenantId)) {
                subTenantCounts.put(tenantId, 0);
            }
        }

        return subTenantCounts;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void setTenantActiveTheme(ExecutionContext context, String tenantId, String themeName) {
        if (themeName == null) {
            throw new JSException("Theme name should not be null!");//TODO i18n
        }
        Tenant tenant = getTenant(context, tenantId);
        if (tenant == null) {
            throw new JSException("Tenant not found : \"" + tenantId + "\"");//TODO i18n
        }
        tenant.setTheme(themeName);
        putTenant(context, tenant);
    }

    @Override
    public Map<DiagnosticAttribute, DiagnosticCallback> getDiagnosticData() {
        return new DiagnosticAttributeBuilder().addDiagnosticAttribute(
                DiagnosticAttributeBuilder.TOTAL_ORGANIZATIONS_COUNT, new DiagnosticCallback<Integer>() {
                    @Override
                    public Integer getDiagnosticAttributeValue() {
                        return getSubTenantsCount(null, ORGANIZATIONS, null);
                    }
                }).build();
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public List<Tenant> getAllSubTenantList(ExecutionContext context, String parentTenantId, String text) {
        return getAllSubTenantList(context, parentTenantId, text, -1);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public List<Tenant> getAllSubTenantList(ExecutionContext context, String parentTenantId, String text,
            int depth) {
        List subTenantList = new ArrayList();

        /* Retrieving parent tenant. */
        RepoTenant parent = getRepoTenant(parentTenantId, false);

        if (parent != null) {
            DetachedCriteria criteria = createSubTenantsCriteria(parent, text, depth);
            criteria.getExecutableCriteria(getSession()).setCacheable(true); // .setCacheMode(CacheMode.REFRESH);
            subTenantList.addAll(getHibernateTemplate().findByCriteria(criteria));
        }

        return toClientTenantList(subTenantList);
    }
}