/* license-start * * Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 3. * * 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 General Public License for more details, at <http://www.gnu.org/licenses/>. * * Contributors: * Crispico - Initial API and implementation * * license-end */ package org.flowerplatform.web.explorer.remote; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.flowerplatform.common.CommonPlugin; import org.flowerplatform.common.file_event.FileEvent; import org.flowerplatform.common.file_event.IFileEventListener; import org.flowerplatform.common.util.Pair; import org.flowerplatform.communication.stateful_service.StatefulServiceInvocationContext; import org.flowerplatform.communication.tree.GenericTreeContext; import org.flowerplatform.communication.tree.IChildrenProvider; import org.flowerplatform.communication.tree.IGenericTreeStatefulServiceAware; import org.flowerplatform.communication.tree.INodeDataProvider; import org.flowerplatform.communication.tree.INodePopulator; import org.flowerplatform.communication.tree.NodeInfo; import org.flowerplatform.communication.tree.remote.DelegatingGenericTreeStatefulService; import org.flowerplatform.communication.tree.remote.GenericTreeStatefulService; import org.flowerplatform.communication.tree.remote.PathFragment; import org.flowerplatform.communication.tree.remote.TreeNode; import org.flowerplatform.web.WebPlugin; import org.flowerplatform.web.entity.WorkingDirectory; import org.flowerplatform.web.entity.impl.WorkingDirectoryImpl; import org.flowerplatform.web.explorer.FsFile_FileSystemChildrenProvider; import org.flowerplatform.web.projects.ProjFile_ProjectChildrenProvider; import org.flowerplatform.web.projects.Project_WorkingDirectoryChildrenProvider; import org.flowerplatform.web.projects.WorkingDirectories_OrganizationChildrenProvider; import org.flowerplatform.web.projects.WorkingDirectory_WorkingDirectoriesChildrenProvider; import org.flowerplatform.web.projects.remote.ProjectsService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ExplorerTreeStatefulService extends DelegatingGenericTreeStatefulService implements IFileEventListener { private static Logger logger = LoggerFactory.getLogger(ExplorerTreeStatefulService.class); public ExplorerTreeStatefulService() throws CoreException { setStatefulClientPrefixId("Explorer"); CommonPlugin.getInstance().getFileEventDispatcher().addFileEventListener(this); { // explorerChildrenProvider IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.flowerplatform.web.explorerChildrenProvider"); for (IConfigurationElement configurationElement : configurationElements) { IChildrenProvider provider = (IChildrenProvider) configurationElement.createExecutableExtension("provider"); for (IConfigurationElement nodeTypeConfigurationElement : configurationElement.getChildren()) { String nodeType = nodeTypeConfigurationElement.getAttribute("nodeType"); List<IChildrenProvider> list = getChildrenProviders().get(nodeType); if (list == null) { list = new ArrayList<IChildrenProvider>(configurationElement.getChildren().length); getChildrenProviders().put(nodeType, list); } if (provider instanceof IGenericTreeStatefulServiceAware) { ((IGenericTreeStatefulServiceAware) provider).setGenericTreeStatefulService(this); } list.add(provider); } } if (logger.isDebugEnabled()) { for (Map.Entry<String, List<IChildrenProvider>> entry : getChildrenProviders().entrySet()) { logger.debug("ExplorerTreeStatefulService: for nodeType = {}, these are the children providers = {}", entry.getKey(), entry.getValue()); } } } { // explorerNodeDataProvider IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.flowerplatform.web.explorerNodeDataProvider"); for (IConfigurationElement configurationElement : configurationElements) { INodeDataProvider provider = (INodeDataProvider) configurationElement.createExecutableExtension("provider"); for (IConfigurationElement nodeTypeConfigurationElement : configurationElement.getChildren()) { String nodeType = nodeTypeConfigurationElement.getAttribute("nodeType"); if (getNodeDataProviders().get(nodeType) != null) { logger.error("Trying to register an INodeDataProvider for nodeType = {}, but another one already exists: {}", nodeType, getNodeDataProviders().get(nodeType)); } else { if (provider instanceof IGenericTreeStatefulServiceAware) { ((IGenericTreeStatefulServiceAware) provider).setGenericTreeStatefulService(this); } getNodeDataProviders().put(nodeType, provider); } } } if (logger.isDebugEnabled()) { for (Map.Entry<String, INodeDataProvider> entry : getNodeDataProviders().entrySet()) { logger.debug("ExplorerTreeStatefulService: for nodeType = {}, this is the node data provider = {}", entry.getKey(), entry.getValue()); } } } { // explorerAdditionalNodePopulator IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.flowerplatform.web.explorerAdditionalNodePopulator"); for (IConfigurationElement configurationElement : configurationElements) { INodePopulator populator = (INodePopulator) configurationElement.createExecutableExtension("populator"); for (IConfigurationElement childConfigurationElement : configurationElement.getChildren()) { if ("nodeType".equals(childConfigurationElement.getName())) { // case #1: add only for a node type String nodeType = childConfigurationElement.getAttribute("nodeType"); addAdditionalNodePopulator(nodeType, populator); } else if ("nodeTypeCategory".equals(childConfigurationElement.getName())) { // case #2: add for a node category type, i.e. for all its node associated node types String nodeTypeCategory = childConfigurationElement.getAttribute("nodeTypeCategory"); List<String> nodeTypes = WebPlugin.getInstance().getNodeTypeCategoryToNodeTypesMap().get(nodeTypeCategory); if (nodeTypes == null) { throw new RuntimeException("There are no node types for node type category = " + nodeTypeCategory); } for (String nodeType : nodeTypes) { addAdditionalNodePopulator(nodeType, populator); } } } } if (logger.isDebugEnabled()) { for (Map.Entry<String, List<INodePopulator>> entry : getAdditionalNodePopulators().entrySet()) { logger.debug("ExplorerTreeStatefulService: for nodeType = {}, these are the additional node populators = {}", entry.getKey(), entry.getValue()); } } } } private void addAdditionalNodePopulator(String nodeType, INodePopulator populator) { List<INodePopulator> populators = getAdditionalNodePopulators().get(nodeType); if (populators == null) { populators = new ArrayList<INodePopulator>(); getAdditionalNodePopulators().put(nodeType, populators); } if (populator instanceof IGenericTreeStatefulServiceAware) { ((IGenericTreeStatefulServiceAware) populator).setGenericTreeStatefulService(this); } populators.add(populator); } /** * @author Tache Razvan Mihai */ @Override public void notify(FileEvent event) { if(event.getEvent() == FileEvent.FILE_CREATED || event.getEvent() == FileEvent.FILE_DELETED || event.getEvent() == FileEvent.FILE_RENAMED) { File file = event.getFile(); File parent = file.getParentFile(); // Update for file system subtree Object node = new Pair<File, String>(parent, FsFile_FileSystemChildrenProvider.NODE_TYPE_FS_FILE); dispatchContentUpdate(node); // update for Special nodes Map<File, Pair<File, IProject>> projectToWorkingDirectoryAndIProjectMap = ProjectsService.getInstance().getProjectToWorkingDirectoryAndIProjectMap(); Map<File, List<File>> workingDirectoryToProjectsMap = ProjectsService.getInstance().getWorkingDirectoryToProjectsMap(); if(workingDirectoryToProjectsMap.containsKey(file)) { // it's an working directory -> parent is workingDirectories } else if(workingDirectoryToProjectsMap.containsKey(parent)) { // it's an project -> parent is working directory String organizationName = ProjectsService.getInstance().getOrganizationNameFromFile(parent); String pathFromOrganization = ProjectsService.getInstance().getRelativePathFromOrganization(parent); WorkingDirectory workingDirectory = ProjectsService.getInstance().getWorkingDirectory(organizationName, pathFromOrganization.substring(0, pathFromOrganization.length() - 1)); dispatchContentUpdate(workingDirectory); } else if(projectToWorkingDirectoryAndIProjectMap.containsKey(parent)) { // it's a projFile with project parent node = new Pair<File, String>(parent, Project_WorkingDirectoryChildrenProvider.NODE_TYPE_PROJECT); dispatchContentUpdate(node); } else { // it may be an indirect projFile -> parent is projFile for(File project : projectToWorkingDirectoryAndIProjectMap.keySet()) { if( parent.getPath().contains(project.getPath())) { node = new Pair<File, String>(parent, ProjFile_ProjectChildrenProvider.NODE_TYPE_PROJ_FILE); dispatchContentUpdate(node); } } } } else if(event.getEvent() == FileEvent.FILE_REFRESHED) { // refresh the tree recursively File file = event.getFile(); Object node = findNode(file); refreshTree(node); } } private Object findNode(File file) { File parent = file.getParentFile(); Object node = null; Map<File, Pair<File, IProject>> projectToWorkingDirectoryAndIProjectMap = ProjectsService.getInstance().getProjectToWorkingDirectoryAndIProjectMap(); Map<File, List<File>> workingDirectoryToProjectsMap = ProjectsService.getInstance().getWorkingDirectoryToProjectsMap(); if(workingDirectoryToProjectsMap.containsKey(file)) { // it's an working directory -> parent is workingDirectories String organizationName = ProjectsService.getInstance().getOrganizationNameFromFile(file); String pathFromOrganization = ProjectsService.getInstance().getRelativePathFromOrganization(file); WorkingDirectory workingDirectory = ProjectsService.getInstance().getWorkingDirectory(organizationName, pathFromOrganization.substring(0, pathFromOrganization.length() - 1)); node = workingDirectory; } else if(workingDirectoryToProjectsMap.containsKey(parent) && projectToWorkingDirectoryAndIProjectMap.containsKey(file)) { // it's an project -> parent is working directory node = new Pair<File, String>(file, Project_WorkingDirectoryChildrenProvider.NODE_TYPE_PROJECT); } else if(projectToWorkingDirectoryAndIProjectMap.containsKey(parent)) { node = new Pair<File, String>(file, ProjFile_ProjectChildrenProvider.NODE_TYPE_PROJ_FILE); } else { // it may be an indirect projFile -> parent is projFile for(File project : projectToWorkingDirectoryAndIProjectMap.keySet()) { if( file.getPath().contains(project.getPath())) { node = new Pair<File, String>(file, ProjFile_ProjectChildrenProvider.NODE_TYPE_PROJ_FILE); } } } if(node == null) { node = new Pair<File, String>(file, FsFile_FileSystemChildrenProvider.NODE_TYPE_FS_FILE); } return node; } public void refreshTree(Object node) { dispatchContentUpdate(node); NodeInfo nodeInfo = visibleNodes.get(node); if (nodeInfo == null) { // not opened, return return; } for(NodeInfo nodeInfoIter : nodeInfo.getChildren()) { refreshTree(nodeInfoIter.getNode()); } } }