class DefaultProjectManager implements ProjectManager {

    private final InternalMavenSession session;
    private final ArtifactManager artifactManager;

    @Inject
    public DefaultProjectManager(InternalMavenSession session, ArtifactManager artifactManager) {
        this.session = session;
        this.artifactManager = artifactManager;
    }

    @Nonnull
    @Override
    public Optional<Path> getPath(Project project) {
        Optional<Artifact> mainArtifact = project.getMainArtifact();
        if (mainArtifact.isPresent()) {
            return artifactManager.getPath(mainArtifact.get());
        }
        return Optional.empty();
    }

    @Nonnull
    @Override
    public Collection<Artifact> getAttachedArtifacts(Project project) {<FILL_FUNCTION_BODY>}

    @Override
    public Collection<Artifact> getAllArtifacts(Project project) {
        ArrayList<Artifact> result = new ArrayList<>(2);
        result.addAll(project.getArtifacts());
        result.addAll(getAttachedArtifacts(project));
        return Collections.unmodifiableCollection(result);
    }

    @Override
    public void attachArtifact(Project project, Artifact artifact, Path path) {
        getMavenProject(project)
                .addAttachedArtifact(RepositoryUtils.toArtifact(
                        ((DefaultProject) project).getSession().toArtifact(artifact)));
        artifactManager.setPath(artifact, path);
    }

    @Override
    public List<Path> getCompileSourceRoots(Project project, ProjectScope scope) {
        MavenProject prj = getMavenProject(nonNull(project, "project"));
        List<String> roots;
        if (nonNull(scope, "scope") == ProjectScope.MAIN) {
            roots = prj.getCompileSourceRoots();
        } else if (scope == ProjectScope.TEST) {
            roots = prj.getTestCompileSourceRoots();
        } else {
            throw new IllegalArgumentException("Unsupported scope " + scope);
        }
        return roots.stream()
                .map(Paths::get)
                .collect(Collectors.collectingAndThen(toList(), Collections::unmodifiableList));
    }

    @Override
    public void addCompileSourceRoot(Project project, ProjectScope scope, Path sourceRoot) {
        MavenProject prj = getMavenProject(nonNull(project, "project"));
        String root = nonNull(sourceRoot, "sourceRoot").toAbsolutePath().toString();
        if (nonNull(scope, "scope") == ProjectScope.MAIN) {
            prj.addCompileSourceRoot(root);
        } else if (scope == ProjectScope.TEST) {
            prj.addTestCompileSourceRoot(root);
        } else {
            throw new IllegalArgumentException("Unsupported scope " + scope);
        }
    }

    @Override
    public List<Resource> getResources(@Nonnull Project project, @Nonnull ProjectScope scope) {
        Project prj = nonNull(project, "project");
        if (nonNull(scope, "scope") == ProjectScope.MAIN) {
            return prj.getBuild().getResources();
        } else if (scope == ProjectScope.TEST) {
            return prj.getBuild().getTestResources();
        } else {
            throw new IllegalArgumentException("Unsupported scope " + scope);
        }
    }

    @Override
    public void addResource(@Nonnull Project project, @Nonnull ProjectScope scope, @Nonnull Resource resource) {
        // TODO: we should not modify the underlying model here, but resources should be stored
        // TODO: in a separate field in the project, however, that could break v3 plugins
        MavenProject prj = getMavenProject(nonNull(project, "project"));
        org.apache.maven.model.Resource res = new org.apache.maven.model.Resource(nonNull(resource, "resource"));
        if (nonNull(scope, "scope") == ProjectScope.MAIN) {
            prj.addResource(res);
        } else if (scope == ProjectScope.TEST) {
            prj.addTestResource(res);
        } else {
            throw new IllegalArgumentException("Unsupported scope " + scope);
        }
    }

    @Override
    public List<RemoteRepository> getRemoteProjectRepositories(Project project) {
        return Collections.unmodifiableList(new MappedList<>(
                ((DefaultProject) project).getProject().getRemoteProjectRepositories(), session::getRemoteRepository));
    }

    @Override
    public List<RemoteRepository> getRemotePluginRepositories(Project project) {
        return Collections.unmodifiableList(new MappedList<>(
                ((DefaultProject) project).getProject().getRemotePluginRepositories(), session::getRemoteRepository));
    }

    @Override
    public void setProperty(Project project, String key, String value) {
        Properties properties = getMavenProject(project).getProperties();
        if (value == null) {
            properties.remove(key);
        } else {
            properties.setProperty(key, value);
        }
    }

    @Override
    public Map<String, String> getProperties(Project project) {
        return Collections.unmodifiableMap(
                new PropertiesAsMap(((DefaultProject) project).getProject().getProperties()));
    }

    @Override
    public Optional<Project> getExecutionProject(Project project) {
        // Session keep tracks of the Project per project id,
        // so we cannot use session.getProject(p) for forked projects
        // which are temporary clones
        return Optional.ofNullable(getMavenProject(project).getExecutionProject())
                .map(p -> new DefaultProject(session, p));
    }

    private MavenProject getMavenProject(Project project) {
        return ((DefaultProject) project).getProject();
    }
}

        InternalMavenSession session = ((DefaultProject) project).getSession();
        Collection<Artifact> attached = map(
                getMavenProject(project).getAttachedArtifacts(),
                a -> session.getArtifact(RepositoryUtils.toArtifact(a)));
        return Collections.unmodifiableCollection(attached);
    
<no_super_class>