class ProjectsImpl implements Projects {

    //Project
    private final List<ProjectImpl> projects;
    //Workspace ids
    private ProjectImpl currentProject;

    public ProjectsImpl() {
        projects = new ArrayList<>();
    }

    public void addProject(ProjectImpl project) {
        synchronized (projects) {
            if (!projects.contains(project)) {
                projects.add(project);
            } else {
                throw new IllegalArgumentException("The project " + project.getUniqueIdentifier() + " already exists");
            }
        }
    }

    public boolean containsProject(Project project) {
        synchronized (projects) {
            return projects.contains(project);
        }
    }

    public ProjectImpl getProjectByIdentifier(String identifier) {
        synchronized (projects) {
            for (Project p : projects) {
                if (p.getUniqueIdentifier().equals(identifier)) {
                    return (ProjectImpl) p;
                }
            }
        }
        return null;
    }

    public void addOrReplaceProject(ProjectImpl project) {
        synchronized (projects) {
            if (projects.contains(project)) {
                projects.remove(project);
                projects.add(project);
            } else {
                ProjectImpl projectWithSameFileName = findProjectByFile(project.getFile());
                if (projectWithSameFileName != null && projectWithSameFileName != project) {
                    projects.remove(projectWithSameFileName);
                }
                projects.add(project);
            }
        }
    }

    private ProjectImpl findProjectByFile(File file) {
        if (file != null) {
            synchronized (projects) {
                for (ProjectImpl p : projects) {
                    if (p.getFile() != null && p.getFile().equals(file)) {
                        return p;
                    }
                }
            }
        }
        return null;
    }

    public void removeProject(ProjectImpl project) {
        synchronized (projects) {
            projects.remove(project);
        }
    }

    @Override
    public ProjectImpl[] getProjects() {
        synchronized (projects) {
            ProjectImpl[] res = projects.toArray(new ProjectImpl[0]);
            Arrays.sort(res);
            return res;
        }
    }

    @Override
    public ProjectImpl getCurrentProject() {
        synchronized (projects) {
            return currentProject;
        }
    }

    public void setCurrentProject(ProjectImpl currentProject) {
        synchronized (projects) {
            this.currentProject = currentProject;
            if (currentProject != null) {
                currentProject.open();
            }
        }
    }

    @Override
    public boolean hasCurrentProject() {
        synchronized (projects) {
            return currentProject != null;
        }
    }

    public void closeCurrentProject() {
        synchronized (projects) {
            if (currentProject != null) {
                currentProject.close();
            }
            this.currentProject = null;
        }
    }

    protected String nextUntitledProjectName() {
        int i = 0;
        while (true) {
            final String name =
                NbBundle.getMessage(ProjectImpl.class, "Project.default.prefix") + (i > 0 ? " " + i : "");
            if (projects.stream().noneMatch((p) -> (p.getName().equals(name)))) {
                return name;
            }
            i++;
        }
    }

    @Override
    public void saveProjects(File file) throws IOException {<FILL_FUNCTION_BODY>}

    @Override
    public void loadProjects(File file) throws IOException {
        synchronized (projects) {
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            if (inputFactory.isPropertySupported("javax.xml.stream.isValidating")) {
                inputFactory.setProperty("javax.xml.stream.isValidating", Boolean.FALSE);
            }
            try (FileInputStream fis = new FileInputStream(file)) {
                XMLStreamReader reader = inputFactory.createXMLStreamReader(fis, "UTF-8");

                boolean end = false;
                while (reader.hasNext() && !end) {
                    int type = reader.next();

                    switch (type) {
                        case XMLStreamReader.START_ELEMENT:
                            String name = reader.getLocalName();
                            if ("project".equalsIgnoreCase(name)) {
                                String filePath = reader.getAttributeValue(null, "file");
                                String id = reader.getAttributeValue(null, "id");
                                String projectName = reader.getAttributeValue(null, "name");
                                String lastOpened = reader.getAttributeValue(null, "lastOpened");

                                if (filePath == null || new File(filePath).exists()) {
                                    ProjectImpl project = new ProjectImpl(id, projectName);
                                    if (filePath != null) {
                                        project.setFile(new File(filePath));
                                    }
                                    if (lastOpened != null) {
                                        project.setLastOpened(Instant.ofEpochMilli(Long.parseLong(lastOpened)));
                                    }
                                    addOrReplaceProject(project);
                                } else {
                                    Logger.getLogger(ProjectsImpl.class.getName())
                                        .warning("Project " + projectName + " file does not exist");
                                }
                            }
                            break;
                        case XMLStreamReader.END_ELEMENT:
                            if ("projects".equalsIgnoreCase(reader.getLocalName())) {
                                end = true;
                            }
                            break;
                    }
                }
                reader.close();
            } catch (XMLStreamException ex) {
                throw new IOException(ex);
            }
        }
    }
}

        synchronized (projects) {
            try (FileOutputStream fos = new FileOutputStream(file)) {
                XMLStreamWriter writer = SaveTask.newXMLWriter(fos);
                writer.writeStartDocument("UTF-8", "1.0");
                writer.writeStartElement("projects");
                for (ProjectImpl p : getProjects()) {
                    if ((!p.hasFile() && p.isOpen()) || (p.hasFile() && p.getFile().exists())) {
                        writer.writeStartElement("project");
                        if (p.hasFile()) {
                            writer.writeAttribute("file", p.getFile().getAbsolutePath());
                        }
                        writer.writeAttribute("id", p.getUniqueIdentifier());
                        writer.writeAttribute("name", p.getName());
                        if (p.getLastOpened() != null) {
                            writer.writeAttribute("lastOpened", String.valueOf(p.getLastOpened().toEpochMilli()));
                        }
                        writer.writeEndElement();
                    } else if (p.hasFile()) {
                        Logger.getLogger(ProjectsImpl.class.getName())
                            .warning("Project " + p.getName() + " file does not exist");
                    }
                }
                writer.writeEndDocument();
            } catch (XMLStreamException ex) {
                throw new IOException(ex);
            }
        }
    
<no_super_class>