org.eclipse.skalli.core.project.ProjectComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.skalli.core.project.ProjectComponent.java

Source

/*******************************************************************************
 * Copyright (c) 2010-2014 SAP AG and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     SAP AG - initial API and implementation
 *******************************************************************************/
package org.eclipse.skalli.core.project;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.eclipse.skalli.commons.CollectionUtils;
import org.eclipse.skalli.commons.UUIDUtils;
import org.eclipse.skalli.model.ByProjectIdComparator;
import org.eclipse.skalli.model.EntityBase;
import org.eclipse.skalli.model.ExtensibleEntityBase;
import org.eclipse.skalli.model.ExtensionEntityBase;
import org.eclipse.skalli.model.Issue;
import org.eclipse.skalli.model.Member;
import org.eclipse.skalli.model.Project;
import org.eclipse.skalli.model.ProjectNature;
import org.eclipse.skalli.model.Severity;
import org.eclipse.skalli.model.ValidationException;
import org.eclipse.skalli.model.ext.commons.PeopleExtension;
import org.eclipse.skalli.services.entity.EntityServiceBase;
import org.eclipse.skalli.services.extension.ExtensionService;
import org.eclipse.skalli.services.extension.ExtensionServices;
import org.eclipse.skalli.services.extension.ExtensionValidator;
import org.eclipse.skalli.services.extension.PropertyValidator;
import org.eclipse.skalli.services.persistence.PersistenceService;
import org.eclipse.skalli.services.project.InvalidParentChainException;
import org.eclipse.skalli.services.project.ProjectService;
import org.eclipse.skalli.services.role.RoleProvider;
import org.eclipse.skalli.services.template.NoSuchTemplateException;
import org.eclipse.skalli.services.template.ProjectTemplate;
import org.eclipse.skalli.services.template.ProjectTemplateService;
import org.eclipse.skalli.services.user.UserServices;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ProjectComponent extends EntityServiceBase<Project> implements ProjectService {

    private static final Logger LOG = LoggerFactory.getLogger(ProjectComponent.class);

    // TODO "central" versioning together with extensibility sucks!
    /*
     * Alternative idea: Instead of a version number just use unique IDs. A
     * migration then defines a set of other migration's ids which have to be
     * applied as a prerequisite. The Migrator then first collects all registered
     * migrations an then sorts them by their prerequisites. Hypothetis: A
     * migration logically cannot depend on another migration if the unique id of
     * that migration is not known. Open issues: - What should be used as a
     * "version" information in the persisted xml? => Maybe something like a
     * checksum (must be stable with respect to the order of calculation)
     */
    private static final int CURRENT_MODEL_VERISON = 23;

    private ProjectTemplateService projectTemplateService;
    private Set<RoleProvider> roleProviders = new HashSet<RoleProvider>();

    protected void activate(ComponentContext context) {
        LOG.info(MessageFormat.format("[ProjectService] {0} : activated",
                (String) context.getProperties().get(ComponentConstants.COMPONENT_NAME)));
    }

    protected void deactivate(ComponentContext context) {
        LOG.info(MessageFormat.format("[ProjectService] {0} : deactivated",
                (String) context.getProperties().get(ComponentConstants.COMPONENT_NAME)));
    }

    protected void bindProjectTemplateService(ProjectTemplateService projectTemplateService) {
        this.projectTemplateService = projectTemplateService;
        LOG.info(MessageFormat.format("bindProjectTemplateService({0})", projectTemplateService)); //$NON-NLS-1$
    }

    protected void unbindProjectTemplateService(ProjectTemplateService projectTemplateService) {
        LOG.info(MessageFormat.format("unbindProjectTemplateService({0})", projectTemplateService)); //$NON-NLS-1$
        this.projectTemplateService = null;
    }

    protected void bindRoleProvider(RoleProvider roleProvider) {
        roleProviders.add(roleProvider);
    }

    protected void unbindRoleProvider(RoleProvider roleProvider) {
        roleProviders.remove(roleProvider);
    }

    @Override
    public Class<Project> getEntityClass() {
        return Project.class;
    }

    @Override
    public int getModelVersion() {
        return CURRENT_MODEL_VERISON;
    }

    @Override
    public ProjectNature getProjectNature(UUID uuid) {
        ProjectTemplate projectTemplate = getProjectTemplate(uuid);
        return projectTemplate != null ? projectTemplate.getProjectNature() : ProjectNature.PROJECT;
    }

    private ProjectTemplate getProjectTemplate(UUID uuid) {
        Project project = getByUUID(uuid);
        if (project == null || projectTemplateService == null) {
            return null;
        }
        return projectTemplateService.getProjectTemplateById(project.getProjectTemplateId());
    }

    @Override
    public Project getProject(String id) {
        return UUIDUtils.isUUID(id) ? getByUUID(UUID.fromString(id)) : getProjectByProjectId(id);
    }

    @Override
    public Project getProjectByProjectId(String projectId) {
        for (Project p : getAll()) {
            if (p.getProjectId().equalsIgnoreCase(projectId)) {
                return p;
            }
        }
        return null;
    }

    @Override
    public List<Project> getProjects(Comparator<Project> c) {
        List<Project> projects = getAll();
        if (c != null) {
            Collections.sort(projects, c);
        }
        return projects;
    }

    @Override
    public List<Project> getProjects(List<UUID> uuids) {
        List<Project> result = new ArrayList<Project>();
        PersistenceService persistence = getPersistenceService();
        for (UUID uuid : uuids) {
            Project project = persistence.getEntity(Project.class, uuid);
            if (project != null) {
                result.add(project);
            }
        }
        return result;
    }

    @Override
    public Map<UUID, List<Project>> getSubProjects() {
        Map<UUID, List<Project>> result = new HashMap<UUID, List<Project>>();
        List<UUID> uuids = new ArrayList<UUID>(keySet());
        for (UUID uuid : uuids) {
            Project project = getByUUID(uuid);
            if (project == null) {
                continue;
            }
            Project parent = project.getParentProject();
            if (parent == null) {
                continue;
            }
            List<Project> subprojects = result.get(parent.getUuid());
            if (subprojects == null) {
                subprojects = new ArrayList<Project>();
                result.put(parent.getUuid(), subprojects);
            }
            subprojects.add(project);
        }
        return result;
    }

    @Override
    public SortedSet<Project> getSubProjects(UUID uuid) {
        return getSubProjects(uuid, null, 1);
    }

    @Override
    public SortedSet<Project> getSubProjects(UUID uuid, Comparator<Project> c) {
        return getSubProjects(uuid, c, 1);
    }

    @Override
    public SortedSet<Project> getSubProjects(UUID uuid, Comparator<Project> c, int depth) {
        depth = depth < 0 ? Integer.MAX_VALUE : depth;
        if (depth == 0) {
            return CollectionUtils.emptySortedSet();
        }

        Project project = getByUUID(uuid);
        if (project == null) {
            return CollectionUtils.emptySortedSet();
        }

        if (depth == 1) {
            return project.getSubProjects(c);
        }

        SortedSet<Project> subprojects = c != null ? new TreeSet<Project>(c)
                : new TreeSet<Project>(new ByProjectIdComparator());

        addSubProjects(project, subprojects, 1, depth);
        return subprojects;
    }

    private void addSubProjects(EntityBase parent, SortedSet<Project> subprojects, int currentDepth, int depth) {
        if (currentDepth > depth) {
            return;
        }
        EntityBase next = (Project) parent.getFirstChild();
        while (next != null) {
            subprojects.add((Project) next);
            addSubProjects(next, subprojects, currentDepth + 1, depth);
            next = next.getNextSibling();
        }
    }

    @Override
    public List<Project> getParentChain(UUID uuid) {
        Project project = getByUUID(uuid);
        if (project == null) {
            project = getDeletedProject(uuid);
            if (project == null) {
                return Collections.emptyList();
            }
        }
        return getParentChain(project);
    }

    private List<Project> getParentChain(Project project) {
        List<Project> result = new LinkedList<Project>();
        result.add(project);
        UUID parentUUID = project.getParentEntityId();
        while (parentUUID != null) {
            Project parent = getByUUID(parentUUID);
            if (parent == null) {
                parent = getDeletedProject(parentUUID);
                if (parent == null) {
                    throw new InvalidParentChainException(project.getUuid(), parentUUID);
                }
            }
            result.add(parent);
            parentUUID = parent.getParentEntityId();
        }
        return result;
    }

    @Override
    public Project getNearestParent(UUID uuid, ProjectNature nature) {
        UUID parentUUID = uuid;
        while (parentUUID != null) {
            Project parent = getByUUID(parentUUID);
            if (parent == null) {
                parent = getDeletedProject(parentUUID);
                if (parent == null) {
                    throw new InvalidParentChainException(uuid, parentUUID);
                }
            }
            String templateId = parent.getProjectTemplateId();
            ProjectTemplate template = projectTemplateService.getProjectTemplateById(templateId);
            if (template == null) {
                throw new NoSuchTemplateException(parentUUID, templateId);
            }
            if (nature.equals(template.getProjectNature())) {
                return parent;
            }
            parentUUID = parent.getParentEntityId();
        }
        return null;
    }

    @Override
    public Set<UUID> deletedSet() {
        return getPersistenceService().deletedSet(Project.class);
    }

    @Override
    public List<Project> getDeletedProjects() {
        return getPersistenceService().getDeletedEntities(Project.class);
    }

    @Override
    public List<Project> getDeletedProjects(Comparator<Project> c) {
        List<Project> projects = getDeletedProjects();
        Collections.sort(projects, c);
        return projects;
    }

    @Override
    public Project getDeletedProject(UUID uuid) {
        return getPersistenceService().getDeletedEntity(Project.class, uuid);
    }

    @Override
    public List<Project> getRootProjects(Comparator<Project> c) {
        List<Project> rootProjects = new ArrayList<Project>();
        List<UUID> uuids = new ArrayList<UUID>(keySet());
        for (UUID uuid : uuids) {
            Project project = getByUUID(uuid);
            if (project == null) {
                continue;
            }
            if (project.getParentEntityId() == null) {
                rootProjects.add(project);
            }
        }
        return rootProjects;
    }

    @Override
    protected void validateEntity(Project entity) throws ValidationException {
        SortedSet<Issue> issues = validate(entity, Severity.FATAL);
        if (issues.size() > 0) {
            throw new ValidationException("Project could not be saved due to the following reasons:", issues);
        }
    }

    /**
    * Validates the given project.
    * Checks basic data like project ID, template, project lead etc.
    * Furthermore, validates the project with the default property/extension validators provided by
    * <code>ExtensionServiceCore</code> and the extension services of the assigned extensions and
    * with the custom validators provided by the {@link ProjectTemplate project template}.
     */
    @Override
    protected SortedSet<Issue> validateEntity(Project project, Severity minSeverity) {
        SortedSet<Issue> issues = new TreeSet<Issue>();

        issues.addAll(validateProjectId(project));
        issues.addAll(validateProjectName(project));
        issues.addAll(validatePeopleExtension(project));

        // ensure that the entity service exists
        UUID projectUUID = project.getUuid();
        ExtensionService<?> extensionService = validateExtensionService(projectUUID, project, issues);

        // ensure that the project template exists
        ProjectTemplate projectTemplate = validateProjectTemplate(project, issues);

        if (extensionService != null && projectTemplate != null) {
            // use the validators provided by the project template/extension services to validate the project
            validateExtension(projectUUID, project, extensionService, projectTemplate, issues, minSeverity);

            // check that all extensions are compatible with the template and vice versa
            if (minSeverity.compareTo(Severity.ERROR) >= 0) {
                validateCompatibility(project, projectTemplate, extensionService, issues);
            }
        }
        return issues;
    }

    private SortedSet<Issue> validatePeopleExtension(Project project) {
        // ensure that the project has a PeopleProjectExt and a project lead
        SortedSet<Issue> issues = new TreeSet<Issue>();
        PeopleExtension peopleExtension = project.getExtension(PeopleExtension.class);
        if (peopleExtension == null) {
            issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), PeopleExtension.class,
                    null, "Project must have a Project Members extension or inherit it from a parent"));
        } else if (peopleExtension.getLeads().isEmpty()) {
            issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), PeopleExtension.class,
                    PeopleExtension.PROPERTY_LEADS, "Project must have a least one Project Lead"));
        }
        return issues;
    }

    private SortedSet<Issue> validateProjectId(Project project) {
        SortedSet<Issue> issues = new TreeSet<Issue>();
        String projectId = project.getProjectId();
        if (StringUtils.isBlank(projectId)) {
            issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), Project.class,
                    Project.PROPERTY_PROJECTID, 1, "Project must have a Project ID"));
        } else {
            if (projectId.trim().length() != projectId.length()) {
                issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), Project.class,
                        Project.PROPERTY_PROJECTID, 2, "Project ID must not have leading or trailing whitespaces"));
            } else {
                for (Project anotherProject : getAll()) {
                    String anotherProjectId = anotherProject.getProjectId();
                    if (projectId.equals(anotherProjectId) && !anotherProject.getUuid().equals(project.getUuid())) {
                        issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), Project.class,
                                Project.PROPERTY_PROJECTID, 3,
                                MessageFormat.format("Project with Project ID ''{0}'' already exists", projectId)));
                        break;
                    }
                }
            }
        }
        return issues;
    }

    private SortedSet<Issue> validateProjectName(Project project) {
        SortedSet<Issue> issues = new TreeSet<Issue>();
        String name = project.getName();
        if (StringUtils.isBlank(name)) {
            issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), Project.class,
                    Project.PROPERTY_NAME, "Projects must have a Display Name"));
        }
        return issues;
    }

    private ProjectTemplate validateProjectTemplate(Project project, Set<Issue> issues) {
        ProjectTemplate projectTemplate = projectTemplateService
                .getProjectTemplateById(project.getProjectTemplateId());
        if (projectTemplate != null) {
            validateDirectParent(projectTemplate, project, issues);
            validateAllowedParents(projectTemplate, project, issues);
        } else {
            issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), Project.class,
                    Project.PROPERTY_TEMPLATEID,
                    MessageFormat.format(
                            "Project references project template ''{0}'' but such a template is not registered",
                            project.getProjectTemplateId())));
        }
        return projectTemplate;
    }

    private void validateDirectParent(ProjectTemplate projectTemplate, Project project, Set<Issue> issues) {
        UUID directParent = projectTemplate.getDirectParent();
        if (directParent != null && !directParent.equals(project.getParentEntityId())) {
            issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), Project.class,
                    Project.PROPERTY_PARENT_ENTITY_ID,
                    MessageFormat.format(
                            "Project assigned to project template ''{0}'' must be direct subproject of project ''{1}''",
                            project.getProjectTemplateId(), directParent)));
        }
    }

    private void validateAllowedParents(ProjectTemplate projectTemplate, Project project, Set<Issue> issues) {
        Set<UUID> allowedParents = projectTemplate.getAllowedParents();
        if (CollectionUtils.isNotBlank(allowedParents)) {
            boolean hasAllowedParent = false;
            for (Project parent : getParentChain(project.getUuid())) {
                if (allowedParents.contains(parent.getUuid())) {
                    hasAllowedParent = true;
                    break;
                }
            }
            if (!hasAllowedParent) {
                issues.add(new Issue(Severity.FATAL, ProjectService.class, project.getUuid(), Project.class,
                        Project.PROPERTY_PARENT_ENTITY_ID,
                        MessageFormat.format(
                                "Project assigned to project template ''{0}'' must be subproject of any of ''{1}''",
                                projectTemplate.getId(), CollectionUtils.toString(allowedParents, ','))));
            }
        }
    }

    private ExtensionService<?> validateExtensionService(UUID projectUUID, ExtensionEntityBase ext,
            Set<Issue> issues) {
        Class<? extends ExtensionEntityBase> extensionClass = ext.getClass();
        ExtensionService<?> extensionService = ExtensionServices.getByExtensionClass(extensionClass);
        if (extensionService == null) {
            issues.add(
                    new Issue(Severity.FATAL, ProjectService.class, projectUUID,
                            MessageFormat.format(
                                    "Project references model extension ''{0}'' but there is no "
                                            + "corresponding extension service registered",
                                    extensionClass.getName())));
        }
        return extensionService;
    }

    private void validateCompatibility(Project project, ProjectTemplate projectTemplate,
            ExtensionService<?> extensionService, Set<Issue> issues) {
        Set<String> allowed = extensionService.getProjectTemplateIds();
        Set<String> included = projectTemplate.getIncludedExtensions();
        Set<String> excluded = projectTemplate.getExcludedExtensions();
        if (allowed != null || included != null || excluded != null) {
            UUID projectUUID = project.getUuid();
            for (ExtensionEntityBase extension : project.getAllExtensions()) {
                String extensionClassName = extension.getClass().getName();
                if (allowed != null && !allowed.contains(projectTemplate.getId())) {
                    issues.add(new Issue(Severity.ERROR, ProjectTemplate.class, projectUUID, extension.getClass(),
                            null,
                            MessageFormat.format(
                                    "{0} projects are not compatible with ''{1}'' extensions. "
                                            + "Disable the extension or select another project template.",
                                    projectTemplate.getDisplayName(), extensionClassName)));
                }
                if (excluded != null && excluded.contains(extensionClassName)
                        || included != null && !included.contains(extensionClassName)) {
                    issues.add(new Issue(Severity.ERROR, ProjectTemplate.class, projectUUID, extension.getClass(),
                            null,
                            MessageFormat.format(
                                    "''{0}'' extensions are not appropriate for {1} projects. "
                                            + "Disable the extension or select another project template.",
                                    extensionClassName, projectTemplate.getDisplayName())));
                }
            }
        }
    }

    private void validateExtension(UUID projectUUID, ExtensionEntityBase ext, ProjectTemplate projectTemplate,
            Set<Issue> issues, Severity minSeverity) {
        ExtensionService<?> extensionService = validateExtensionService(projectUUID, ext, issues);
        if (extensionService != null) {
            validateExtension(projectUUID, ext, extensionService, projectTemplate, issues, minSeverity);
        }
    }

    private void validateExtension(UUID projectUUID, ExtensionEntityBase ext, ExtensionService<?> extensionService,
            ProjectTemplate projectTemplate, Set<Issue> issues, Severity minSeverity) {
        String extensionClassName = extensionService.getExtensionClass().getName();

        Map<String, String> captions = new HashMap<String, String>();

        Set<String> propertyNames = ext.getPropertyNames();
        for (String propertyName : propertyNames) {

            // determine a suitable caption for the property, either from the template or the
            // extension service; if neither is availablle, pass null to the validators
            String caption = projectTemplate.getCaption(extensionClassName, propertyName);
            if (StringUtils.isBlank(caption)) {
                caption = extensionService.getCaption(propertyName);
            }
            captions.put(propertyName, caption);

            List<PropertyValidator> propertyValidators = new ArrayList<PropertyValidator>();
            List<PropertyValidator> defaultValidators = extensionService.getPropertyValidators(propertyName,
                    caption);
            if (defaultValidators == null) {
                LOG.warn(MessageFormat.format(
                        "{0}#getPropertyValidators({1}) returned null, but is expected to return an empty set",
                        extensionService.getClass().getName(), propertyName));
            } else {
                propertyValidators.addAll(defaultValidators);
            }
            List<PropertyValidator> customValidators = projectTemplate.getPropertyValidators(extensionClassName,
                    propertyName);
            if (customValidators == null) {
                LOG.warn(MessageFormat.format(
                        "{0}#getPropertyValidators({1}, {2}) returned null, but is expected to return an empty set",
                        projectTemplate.getClass().getName(), extensionClassName, propertyName));
            } else {
                propertyValidators.addAll(customValidators);
            }
            for (PropertyValidator propertyValidator : propertyValidators) {
                try {
                    issues.addAll(
                            propertyValidator.validate(projectUUID, ext.getProperty(propertyName), minSeverity));
                } catch (RuntimeException e) {
                    LOG.error(MessageFormat.format("{0}#validate on project {1} threw an exception",
                            propertyValidator.getClass().getName(), projectUUID), e);
                }
            }
        }

        issues.addAll(validateExtensionServiceExtensionValidators(projectUUID, ext, extensionService,
                projectTemplate, minSeverity, captions));
        issues.addAll(validateProjectTemplateExtensionValidators(projectUUID, ext, projectTemplate, minSeverity));

        // if this extension is extensible, recursively validate all extensions
        if (ext instanceof ExtensibleEntityBase) {
            for (ExtensionEntityBase extension : ((ExtensibleEntityBase) ext).getAllExtensions()) {
                validateExtension(projectUUID, extension, projectTemplate, issues, minSeverity);
            }
        }
    }

    private Set<Issue> validateExtensionServiceExtensionValidators(UUID projectUUID, ExtensionEntityBase ext,
            ExtensionService<?> extensionService, ProjectTemplate projectTemplate, Severity minSeverity,
            Map<String, String> captions) {
        Set<Issue> issues = new TreeSet<Issue>();

        List<? extends ExtensionValidator<?>> extensionValidators = extensionService
                .getExtensionValidators(captions);
        if (extensionValidators == null) {
            LOG.warn(MessageFormat.format(
                    "{0}#getExtensionValidators() returned null, but is expected to return an empty set",
                    projectTemplate.getClass().getName()));
        } else {
            for (ExtensionValidator<?> extensionValidator : extensionValidators) {
                try {
                    issues.addAll(extensionValidator.validate(projectUUID, ext, minSeverity));
                } catch (RuntimeException e) {
                    LOG.error(MessageFormat.format("{0}#validate on project {1} threw an exception",
                            extensionValidator.getClass().getName(), projectUUID), e);
                }
            }
        }
        return issues;
    }

    private Set<Issue> validateProjectTemplateExtensionValidators(UUID uuid, ExtensionEntityBase ext,
            ProjectTemplate projectTemplate, Severity minSeverity) {
        Set<Issue> issues = new TreeSet<Issue>();
        List<ExtensionValidator<?>> extentionValidators = projectTemplate
                .getExtensionValidators(ext.getClass().getName());
        if (extentionValidators == null) {
            LOG.warn(MessageFormat.format(
                    "{0}#getExtensionValidators({1}) returned null, but is expected to return an empty set",
                    projectTemplate.getClass().getName(), ext.getClass().getName()));
        } else {
            for (ExtensionValidator<?> extensionValidator : extentionValidators) {
                try {
                    issues.addAll(extensionValidator.validate(uuid, ext, minSeverity));
                } catch (RuntimeException e) {
                    LOG.error(MessageFormat.format("{0}#validate on project {1} threw an exception",
                            extensionValidator.getClass().getName(), uuid), e);
                }
            }
        }
        return issues;
    }

    @Override
    public SortedSet<Member> getMembers(UUID uuid) {
        TreeSet<Member> ret = new TreeSet<Member>();
        Project project = getByUUID(uuid);
        if (project != null) {
            for (RoleProvider roleProvider : roleProviders) {
                ret.addAll(roleProvider.getMembers(project));
            }
        }
        return ret;
    }

    @Override
    public SortedSet<Member> getMembers(UUID uuid, String... roles) {
        TreeSet<Member> ret = new TreeSet<Member>();
        Project project = getByUUID(uuid);
        if (project != null) {
            for (RoleProvider roleProvider : roleProviders) {
                ret.addAll(roleProvider.getMembers(project, roles));
            }
        }
        return ret;
    }

    @Override
    public Map<String, SortedSet<Member>> getMembersByRole(UUID uuid) {
        Map<String, SortedSet<Member>> ret = new HashMap<String, SortedSet<Member>>();
        Project project = getByUUID(uuid);
        if (project != null) {
            for (RoleProvider roleProvider : roleProviders) {
                ret.putAll(roleProvider.getMembersByRole(project));
            }
        }
        return ret;
    }

    @Override
    public Project createProject(final String templateId, final String userId) {
        final Project project = (StringUtils.isNotBlank(templateId)) ? new Project(templateId) : new Project();
        project.setUuid(UUID.randomUUID());

        if (UserServices.getUser(userId) != null) {
            PeopleExtension peopleExt = new PeopleExtension();
            peopleExt.getLeads().add(new Member(userId));
            project.addExtension(peopleExt);
        }

        final ProjectTemplate template = projectTemplateService.getProjectTemplateById(templateId);

        if (template != null) {
            for (Class<? extends ExtensionEntityBase> extensionClass : projectTemplateService
                    .getSelectableExtensions(template, null)) {
                String extensionClassName = extensionClass.getName();
                if (template.isEnabled(extensionClassName)) {
                    try {
                        if (project.getExtension(extensionClass) == null) {
                            project.addExtension(extensionClass.cast(extensionClass.newInstance()));
                        }
                    } catch (InstantiationException e) {
                        LOG.warn(MessageFormat.format("Extension ''{0}'' could not be instantiated: {1}",
                                extensionClassName, e.getMessage()));
                    } catch (IllegalAccessException e) {
                        LOG.warn(MessageFormat.format("Extension ''{0}'' could not be instantiated: {1}",
                                extensionClassName, e.getMessage()));
                    }
                }
            }
        }

        return project;
    }
}