/** * Copyright 2012 Universitat Pompeu Fabra. * * 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.onexus.resource.manager.internal; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.monitor.FileAlterationListenerAdaptor; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; import org.onexus.resource.api.IResourceListener; import org.onexus.resource.api.IResourceSerializer; import org.onexus.resource.api.Project; import org.onexus.resource.manager.internal.providers.AbstractProjectProvider; import org.onexus.resource.manager.internal.providers.ProjectProviderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; public class ProjectsContainer { private static final Logger LOGGER = LoggerFactory.getLogger(ProjectsContainer.class); public static final String ONEXUS_FOLDER = System.getProperty("user.home") + File.separator + ".onexus"; public static final String ONEXUS_PROJECTS_SETTINGS = "projects.ini"; public static final String ONEXUS_PROJECTS_FOLDER = ONEXUS_FOLDER + File.separator + "projects"; private File propertiesFile; private FileAlterationMonitor monitor; private Properties properties; private ProjectProviderFactory providerFactory; private Map<String, AbstractProjectProvider> providers; // Listeners private List<IResourceListener> listeners = new ArrayList<IResourceListener>(); public ProjectsContainer(IResourceSerializer serializer, PluginLoader pluginLoader) { super(); File onexusFolder = new File(ONEXUS_FOLDER); File projectsFolder = new File(ONEXUS_PROJECTS_FOLDER); propertiesFile = new File(onexusFolder, ONEXUS_PROJECTS_SETTINGS); monitor = new FileAlterationMonitor(2000); if (!onexusFolder.exists()) { onexusFolder.mkdir(); } if (!projectsFolder.exists()) { projectsFolder.mkdir(); } try { if (!propertiesFile.exists()) { propertiesFile.createNewFile(); } this.providerFactory = new ProjectProviderFactory(serializer, pluginLoader, monitor, listeners); this.providers = new ConcurrentHashMap<String, AbstractProjectProvider>(); init(); } catch (IOException e) { throw new RuntimeException("Loading projects file '" + ONEXUS_PROJECTS_SETTINGS + "'", e); } FileAlterationObserver observer = new FileAlterationObserver(onexusFolder, FileFilterUtils.nameFileFilter(ONEXUS_PROJECTS_SETTINGS)); observer.addListener(new FileAlterationListenerAdaptor() { @Override public void onFileChange(File file) { try { ProjectsContainer.this.init(); } catch (IOException e) { LOGGER.error("Loading projects file '" + ONEXUS_PROJECTS_SETTINGS + "'", e); } } }); monitor.addObserver(observer); try { monitor.start(); } catch (Exception e) { LOGGER.error("On start projects file monitor", e); } } public void destroy() { try { monitor.stop(); } catch (Exception e) { LOGGER.error("On stop projects file monitor", e); } } private void init() throws IOException { this.properties = new Properties(); properties.load(new FileInputStream(propertiesFile)); for (String projectUrl : getProjectUrls()) { String projectPath = null; String projectName = null; try { String projectProperty[] = properties.getProperty(projectUrl).split(","); projectPath = projectProperty[0]; projectName = projectProperty.length == 2 ? projectProperty[1] : Integer.toHexString(projectUrl.hashCode()); File projectFolder = new File(projectPath); AbstractProjectProvider previousProvider = providers.get(projectUrl); if (previousProvider != null && previousProvider.getProjectFolder().equals(projectFolder) && previousProvider.getProject().getName().equals(projectName) ) { // This project is already registered, skip it continue; } AbstractProjectProvider provider = providerFactory.newProjectProvider(projectName, projectUrl, projectFolder); providers.put(projectUrl, provider); if (previousProvider == null) { onProjectCreate(provider.getProject()); } else { onProjectChange(provider.getProject()); } } catch (Exception e) { LOGGER.error("Loading project '" + projectUrl + "' named '" + projectName + "' at " + projectPath, e); } } // Remove deleted projects List<String> deletedProjects = new ArrayList<String>(providers.keySet()); deletedProjects.removeAll(getProjectUrls()); for (String deletedProject : deletedProjects) { onProjectDelete(providers.get(deletedProject).getProject()); providers.remove(deletedProject); } } public Collection<String> getProjectUrls() { return properties.stringPropertyNames(); } public AbstractProjectProvider getProjectProvider(String projectUri) { return providers.get(projectUri); } public AbstractProjectProvider importProject(String projectName, String projectUri) { File defaultProjectFolder = newProjectFolder(projectUri); AbstractProjectProvider provider = providerFactory.newProjectProvider(projectName, projectUri, defaultProjectFolder); if (provider != null) { providers.put(projectUri, provider); properties.setProperty(projectUri, provider.getProjectFolder().getAbsolutePath() + "," + projectName); try { properties.store(new FileOutputStream(new File(new File(ONEXUS_FOLDER), ONEXUS_PROJECTS_SETTINGS)), null); } catch (FileNotFoundException e) { LOGGER.error(e.getMessage()); } catch (IOException e) { LOGGER.error(e.getMessage()); } } onProjectCreate(provider.getProject()); return provider; } private File newProjectFolder(String projectUri) { return new File(new File(ONEXUS_PROJECTS_FOLDER), Integer.toHexString(projectUri.hashCode())); } void addResourceListener(IResourceListener resourceListener) { listeners.add(resourceListener); } private void onProjectCreate(final Project project) { LOGGER.info("Project '" + project.getName() + "' created."); new Thread(new Runnable() { @Override public void run() { for (IResourceListener listener : listeners) { listener.onProjectCreate(project); } } }).start(); } private void onProjectChange(final Project project) { LOGGER.info("Project '" + project.getName() + "' changed."); new Thread(new Runnable() { @Override public void run() { for (IResourceListener listener : listeners) { listener.onProjectChange(project); } } }).start(); } private void onProjectDelete(final Project project) { LOGGER.info("Project '" + project.getName() + "' deleted."); for (IResourceListener listener : listeners) { listener.onProjectDelete(project); } } public void bundleCreated(long bundleId) { for (AbstractProjectProvider provider : providers.values()) { if (provider.dependsOnBundle(bundleId)) { provider.loadProject(); onProjectChange(provider.getProject()); } } } public void bundleUninstalled(long bundleId) { } }