/******************************************************************************* * Copyright (c) 2010 Neil Bartlett. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Neil Bartlett - initial API and implementation *******************************************************************************/ package bndtools.editor.exports; import java.io.ByteArrayInputStream; import java.io.File; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.bndtools.api.ILogger; import org.bndtools.api.Logger; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.ide.ResourceUtil; import aQute.bnd.build.Project; import aQute.bnd.build.model.BndEditModel; import aQute.bnd.build.model.clauses.ExportedPackage; import aQute.bnd.header.Attrs; import aQute.bnd.osgi.Constants; import bndtools.Plugin; import bndtools.central.Central; import bndtools.editor.contents.PackageInfoDialog; import bndtools.editor.contents.PackageInfoStyle; import bndtools.editor.contents.PackageInfoDialog.FileVersionTuple; import bndtools.editor.pkgpatterns.PkgPatternsListPart; import bndtools.internal.pkgselection.IPackageFilter; import bndtools.internal.pkgselection.JavaSearchScopePackageLister; import bndtools.internal.pkgselection.PackageSelectionDialog; import bndtools.preferences.BndPreferences; public class ExportPatternsListPart extends PkgPatternsListPart<ExportedPackage> { private static final ILogger logger = Logger.getLogger(ExportPatternsListPart.class); public ExportPatternsListPart(Composite parent, FormToolkit toolkit, int style) { super(parent, toolkit, style, Constants.EXPORT_PACKAGE, "Export Packages", new ExportedPackageLabelProvider()); } @Override protected Collection<ExportedPackage> generateClauses() { return selectPackagesToAdd(); } protected List<ExportedPackage> selectPackagesToAdd() { List<ExportedPackage> added = null; final IPackageFilter filter = new IPackageFilter() { @Override public boolean select(String packageName) { if (packageName.equals("java") || packageName.startsWith("java.")) return false; // TODO: check already included patterns return true; } }; IFormPage page = (IFormPage) getManagedForm().getContainer(); IWorkbenchWindow window = page.getEditorSite().getWorkbenchWindow(); // Prepare the package lister from the Java project IProject project = ResourceUtil.getResource(page.getEditorInput()).getProject(); IJavaProject javaProject = JavaCore.create(project); IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(new IJavaElement[] { javaProject }); JavaSearchScopePackageLister packageLister = new JavaSearchScopePackageLister(searchScope, window); // Create and open the dialog PackageSelectionDialog dialog = new PackageSelectionDialog(window.getShell(), packageLister, filter, "Select new packages to export from the bundle."); dialog.setSourceOnly(true); dialog.setMultipleSelection(true); if (dialog.open() == Window.OK) { Object[] results = dialog.getResult(); added = new LinkedList<ExportedPackage>(); // Select the results for (Object result : results) { String newPackageName = (String) result; ExportedPackage newPackage = new ExportedPackage(newPackageName, new Attrs()); added.add(newPackage); } } return added; } @Override protected void doAddClauses(Collection< ? extends ExportedPackage> pkgs, int index, boolean select) { List<FileVersionTuple> missingPkgInfoDirs; try { missingPkgInfoDirs = new ArrayList<FileVersionTuple>(findSourcePackagesWithoutPackageInfo(pkgs)); } catch (Exception e) { ErrorDialog.openError(getManagedForm().getForm().getShell(), "Error", null, new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0, "Error finding source package for exported 1packages.", e)); missingPkgInfoDirs = Collections.emptyList(); } List<FileVersionTuple> generatePkgInfoDirs = new ArrayList<FileVersionTuple>(missingPkgInfoDirs.size()); BndPreferences prefs = new BndPreferences(); boolean noAskPackageInfo = prefs.getNoAskPackageInfo(); if (noAskPackageInfo || missingPkgInfoDirs.isEmpty()) { generatePkgInfoDirs.addAll(missingPkgInfoDirs); } else { PackageInfoDialog dlg = new PackageInfoDialog(getSection().getShell(), missingPkgInfoDirs); if (dlg.open() == Window.CANCEL) return; prefs.setNoAskPackageInfo(dlg.isDontAsk()); generatePkgInfoDirs.addAll(dlg.getSelectedPackageDirs()); } try { generatePackageInfos(generatePkgInfoDirs); } catch (CoreException e) { ErrorDialog.openError(getManagedForm().getForm().getShell(), "Error", null, new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0, "Error generated packageinfo files.", e)); } // Actually add the new exports super.doAddClauses(pkgs, index, select); } private Collection<FileVersionTuple> findSourcePackagesWithoutPackageInfo(Collection< ? extends ExportedPackage> pkgs) throws Exception { Map<String,FileVersionTuple> result = new HashMap<String,FileVersionTuple>(); Project project = getProject(); if (project != null) { Collection<File> sourceDirs = project.getSourcePath(); for (File sourceDir : sourceDirs) { for (ExportedPackage pkg : pkgs) { if (!result.containsKey(pkg.getName())) { File pkgDir = new File(sourceDir, pkg.getName().replace('.', '/')); if (pkgDir.isDirectory()) { PackageInfoStyle existingPkgInfo = PackageInfoStyle.findExisting(pkgDir); if (existingPkgInfo == null) result.put(pkg.getName(), new FileVersionTuple(pkg.getName(), pkgDir)); } } } } } return result.values(); } private static void generatePackageInfos(final Collection< ? extends FileVersionTuple> pkgs) throws CoreException { final IWorkspaceRunnable wsOperation = new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { SubMonitor progress = SubMonitor.convert(monitor, pkgs.size()); MultiStatus status = new MultiStatus(Plugin.PLUGIN_ID, 0, "Errors occurred while creating packageinfo files.", null); for (FileVersionTuple pkg : pkgs) { IContainer[] locations = ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(pkg.getFile().toURI()); if (locations != null && locations.length > 0) { IContainer container = locations[0]; PackageInfoStyle packageInfoStyle = PackageInfoStyle.calculatePackageInfoStyle(container.getProject()); IFile pkgInfoFile = container.getFile(new Path(packageInfoStyle.getFileName())); try { String formattedPackageInfo = packageInfoStyle.format(pkg.getVersion(), pkg.getName()); ByteArrayInputStream input = new ByteArrayInputStream(formattedPackageInfo.getBytes("UTF-8")); if (pkgInfoFile.exists()) pkgInfoFile.setContents(input, false, true, progress.newChild(1, 0)); else pkgInfoFile.create(input, false, progress.newChild(1, 0)); } catch (CoreException e) { status.add(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0, "Error creating file " + pkgInfoFile.getFullPath(), e)); } catch (UnsupportedEncodingException e) { /* just ignore, should never happen */ } } } if (!status.isOK()) throw new CoreException(status); } }; IRunnableWithProgress uiOperation = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { ResourcesPlugin.getWorkspace().run(wsOperation, monitor); } catch (CoreException e) { throw new InvocationTargetException(e); } } }; try { PlatformUI.getWorkbench().getActiveWorkbenchWindow().run(true, true, uiOperation); } catch (InvocationTargetException e) { throw (CoreException) e.getTargetException(); } catch (InterruptedException e) { // ignore } } @Override protected ExportedPackage newHeaderClause(String text) { return new ExportedPackage(text, new Attrs()); } @Override protected List<ExportedPackage> loadFromModel(BndEditModel model) { return model.getExportedPackages(); } @Override protected void saveToModel(BndEditModel model, List< ? extends ExportedPackage> clauses) { model.setExportedPackages(clauses); } Project getProject() { Project project = null; try { BndEditModel model = (BndEditModel) getManagedForm().getInput(); File bndFile = model.getBndResource(); IPath path = Central.toPath(bndFile); IFile resource = ResourcesPlugin.getWorkspace().getRoot().getFile(path); project = Central.getProject(resource.getProject()); } catch (Exception e) { logger.logError("Error getting project from editor model", e); } return project; } }