package cideplus.ui.export.action; import java.io.IOException; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.swt.widgets.Shell; import cideplus.model.ASTNodeReference; import cideplus.model.Feature; import cideplus.model.exceptions.FeatureNotFoundException; import cideplus.ui.configuration.ICompilationUnitFeaturesManager; import cideplus.ui.configuration.FeaturesConfigurationUtil; import cideplus.ui.configuration.IFeaturesManager; public class Exporter { private Shell shell; private IJavaProject project; private int projectJavaCount; private IFeaturesManager featuresManager; private Set<Feature> exportedFeatures; public Exporter(Shell shell, IJavaProject project, Set<Feature> features) { this.shell = shell; this.project = project; this.exportedFeatures = features; featuresManager = FeaturesConfigurationUtil.getFeaturesManager(project.getProject()); } public int getFileCount(IProgressMonitor monitor) throws CoreException{ monitor.beginTask("Preparing to export...", IProgressMonitor.UNKNOWN); countProjectFiles(); monitor.done(); return projectJavaCount; } /** * Exporta os arquivos para um mapa com o nome e conte�do de cada arquivo exportado.<BR> * Para cada arquivo � adicionado 3 ao trabalho do monitor<BR> * O m�todo getFileCount retorna o n�mero de arquivos encontrados, esse valor � o mesmo do n�mero de progressos desse m�todo (mas cada progresso conta 3 unidades). * Os m�todos beginTask e done do objeto monitor, devem ser chamados fora desse m�todo. Um antes e o outro depois respectivamente. * @param monitor * @return * @throws CoreException * @throws FeatureNotFoundException * @throws IOException */ public Map<String, byte[]> getExportedFiles(IProgressMonitor monitor) throws CoreException, IOException, FeatureNotFoundException { IPackageFragmentRoot[] allPackageFragmentRoots = project.getAllPackageFragmentRoots(); Map<String, byte[]> result = new LinkedHashMap<String, byte[]>(); for (IPackageFragmentRoot iPackageFragmentRoot : allPackageFragmentRoots) { if(iPackageFragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE){ //todos os package roots que s�o source folders... monitor.setTaskName("Exporting... "+iPackageFragmentRoot.getElementName()); IJavaElement[] children = iPackageFragmentRoot.getChildren(); checkChildren(result, children, monitor); } } return result; } private void checkChildren(Map<String, byte[]> result, IJavaElement[] children, IProgressMonitor monitor) throws CoreException, IOException, FeatureNotFoundException { for (IJavaElement iJavaElement : children) { if(iJavaElement instanceof ICompilationUnit){ exportJavaFile(result, (ICompilationUnit)iJavaElement, monitor); } else { if(iJavaElement instanceof IPackageFragment){ checkChildren(result, ((IPackageFragment)iJavaElement).getChildren(), monitor); } } } } /** * Exporta determinado arquivo Java para o mapa de arquivos * @param result * @param iJavaElement * @param monitor * @throws CoreException * @throws FeatureNotFoundException * @throws IOException */ private void exportJavaFile(Map<String, byte[]> result, ICompilationUnit comp, IProgressMonitor monitor) throws IOException, FeatureNotFoundException, CoreException { if(monitor.isCanceled()){ throw new OperationCanceledException(); } monitor.setTaskName("Exporting... "+comp.getParent().getElementName()+"."+stripExtension(comp.getElementName())); ICompilationUnitFeaturesManager manager = featuresManager.getManagerForFile(comp); Set<ASTNodeReference> nodesToRemove = getNodesToRemove(manager); Set<ASTNodeReference> nodeReferences = removeOverridenAndOrder(nodesToRemove); String source = comp.getSource(); for (Iterator<ASTNodeReference> iterator = nodeReferences.iterator(); iterator.hasNext();) { ASTNodeReference astNodeReference = iterator.next(); //elimina do source o c�digo do n� que n�o ser� exportado source = source.substring(0, astNodeReference.getOffset()) + source.substring(astNodeReference.getOffset() + astNodeReference.getByteCount(), source.length()); } //CompilationUnit ast = cideplus.automation.Util.getAst(comp, false); result.put(comp.getPath().toString(), source.getBytes()); monitor.worked(3); } /** * Retorna a lista de n�s que devem ser removidos * @param manager * @return */ protected Set<ASTNodeReference> getNodesToRemove(ICompilationUnitFeaturesManager manager) { Set<ASTNodeReference> allNodeReferences = manager.getNodeReferences(); Set<ASTNodeReference> nodesToRemove = new HashSet<ASTNodeReference>(); for (Iterator<ASTNodeReference> iterator = allNodeReferences.iterator(); iterator.hasNext();) { ASTNodeReference astNodeReference = iterator.next(); //iremos remover os items que n�o ser�o exportados... � importante que os n�s estejam ordenados por offset decrescente Set<Feature> nodeFeatures = manager.getFeatures(astNodeReference); nodeFeatures.removeAll(exportedFeatures); if(nodeFeatures.size() > 0){ //se ao remover da lista de features do n�.. a lista de features a ser exportada.. //sobrar alguma feature, significa que o n� tem uma feature que n�o est� sendo exportada... //ent�o vamos remover esse n� nodesToRemove.add(astNodeReference); } } return nodesToRemove; } /** * Remove as features que est�o se sobrescrevendo... � utilizado o offset e o length para o c�lculo. * Ordena os n�s em ordem decrescente de offset. Ou seja, offsets maiores vem primeiro. * @param nodeReferences * @return */ private Set<ASTNodeReference> removeOverridenAndOrder(Set<ASTNodeReference> nodeReferences) { TreeSet<ASTNodeReference> result = new TreeSet<ASTNodeReference>(new Comparator<ASTNodeReference>() { public int compare(ASTNodeReference o1, ASTNodeReference o2) { return o2.getOffset() - o1.getOffset();//ordem decrescente de offset } }); result.addAll(nodeReferences); for (Iterator<ASTNodeReference> iterator1 = result.iterator(); iterator1.hasNext();) { ASTNodeReference astNodeReference1 = iterator1.next(); for (ASTNodeReference astNodeReference2 : result) { if(astNodeReference1.isChild(astNodeReference2)){ iterator1.remove(); break; } } } return result; } private void countProjectFiles() throws CoreException { projectJavaCount = 0; project.getProject().accept(new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if(resource.getName().endsWith(".java")){ projectJavaCount++; } return true; } }); } private String stripExtension(String elementName) { return elementName.substring(0, elementName.indexOf(".")); } }