package org.activiti.designer.util.workspace; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.bpmn2.Process; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; public class ActivitiWorkspaceUtil { private static Map<IResource, CacheData> cache = new HashMap<IResource, CacheData>(); /** * Returns a Set of projects that have the provided project nature. The result * contains only projects that are open and available for use. * * @param natureId * the id of the project nature required * @return a set of projects with the nature, or an empty set if none are * found */ public static final Set<IProject> getOpenProjectsWithNature(final String natureId) { final Set<IProject> result = new HashSet<IProject>(); final IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (final IProject project : projects) { try { if (project.isOpen() && project.hasNature(natureId)) { result.add(project); } } catch (CoreException e) { // don't handle; project may be closed and shouldn't be considered } } return result; } public static final Set<IFile> getBPMNResourcesById(String callElement) { final Set<IFile> result = new HashSet<IFile>(); final Set<IFile> allBPMNFiles = getBPMNResources(); for (final IFile resource : allBPMNFiles) { if (!cache.containsKey(resource)) { cache.put(resource, new CacheData(getProcessIds(resource), resource.getModificationStamp())); } final CacheData data = cache.get(resource); if (data.cacheIsExpired(resource.getModificationStamp())) { data.setProcessIds(getProcessIds(resource)); data.setLastModified(resource.getModificationStamp()); } if (data.hasProcessId(callElement)) { result.add(resource); } } return result; } private static Set<String> getProcessIds(IFile resource) { final Set<String> result = new HashSet<String>(); final BpmnProcessParser parser = new BpmnProcessParser(resource); final Set<Process> processes = parser.getProcesses(); for (final Process process : processes) { result.add(process.getId()); } return result; } public static final Set<IFile> getBPMNResources() { final Set<IFile> result = new HashSet<IFile>(); final Set<IProject> projects = ActivitiWorkspaceUtil.getOpenProjectsWithNature("org.activiti.designer.nature"); for (final IProject project : projects) { final BPMNResourceVisitor visitor = new BPMNResourceVisitor(); try { project.accept(visitor); } catch (CoreException e) { e.printStackTrace(); } result.addAll(visitor.getResources()); } return result; } private static class BPMNResourceVisitor implements IResourceVisitor { private static final Set<String> IGNORED_ROOT_SEGMENTS = new HashSet<String>(); private Set<IFile> visitResults = new HashSet<IFile>(); static { IGNORED_ROOT_SEGMENTS.add("target"); IGNORED_ROOT_SEGMENTS.add("tempbar"); } @Override public boolean visit(IResource resource) throws CoreException { // TODO externalize extension to method if (isIgnoredResource(resource)) { return false; } if (resource instanceof IFile && resource.getName().endsWith(".bpmn20.xml")) { visitResults.add((IFile) resource); } return true; } private boolean isIgnoredResource(IResource resource) { boolean result = false; if (resource instanceof IFolder) { final String rootSegment = ((IFolder) resource).getFullPath().segment(1); if (IGNORED_ROOT_SEGMENTS.contains(rootSegment)) { result = true; } } return result; } public Set<IFile> getResources() { return visitResults; } } private static class CacheData { private Set<String> processIds; private Long lastModified; public CacheData(final Set<String> bpmnIds, final Long lastModified) { this.processIds = bpmnIds; this.lastModified = lastModified; } public Set<String> getProcessIds() { return processIds; } public void setProcessIds(Set<String> processIds) { this.processIds = processIds; } public Long getLastModified() { return lastModified; } public void setLastModified(Long lastModified) { this.lastModified = lastModified; } public boolean cacheIsExpired(final Long lastModified) { return this.lastModified.compareTo(lastModified) < 0; } public boolean hasProcessId(final String processId) { return processIds.contains(processId); } } }