Workspace repository now filters exports that project doesn't actually contain in "compile time" resolution mode (FELIX-1502)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@917993 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/common/core/src/org/apache/felix/sigil/repository/ResolutionConfig.java b/sigil/common/core/src/org/apache/felix/sigil/repository/ResolutionConfig.java
index 54571b5..1ffe3ac 100644
--- a/sigil/common/core/src/org/apache/felix/sigil/repository/ResolutionConfig.java
+++ b/sigil/common/core/src/org/apache/felix/sigil/repository/ResolutionConfig.java
@@ -31,6 +31,7 @@
public static final int INDEXED_ONLY = 8;
/** Return only bundles that are stored or cached locally */
public static final int LOCAL_ONLY = 16;
+ public static final int COMPILE_TIME = 32;
public ResolutionConfig()
@@ -74,4 +75,10 @@
// TODO Auto-generated method stub
return false;
}
+
+
+ public boolean isCompileTime()
+ {
+ return ( options & COMPILE_TIME ) != 0;
+ }
}
diff --git a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepository.java b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepository.java
index 7d290ad..80df5df 100644
--- a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepository.java
+++ b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepository.java
@@ -20,145 +20,140 @@
package org.apache.felix.sigil.eclipse.internal.repository.eclipse;
-import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import org.apache.felix.sigil.eclipse.SigilCore;
import org.apache.felix.sigil.eclipse.model.project.ISigilProjectModel;
import org.apache.felix.sigil.model.eclipse.ISigilBundle;
+import org.apache.felix.sigil.model.osgi.IPackageExport;
import org.apache.felix.sigil.repository.AbstractBundleRepository;
import org.apache.felix.sigil.repository.IRepositoryVisitor;
+import org.apache.felix.sigil.repository.ResolutionConfig;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
-
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
public class WorkspaceRepository extends AbstractBundleRepository implements IResourceChangeListener
{
private static final int UPDATE_MASK = IResourceDelta.CONTENT | IResourceDelta.DESCRIPTION | IResourceDelta.OPEN;
- private ISigilBundle[] bundles;
-
public WorkspaceRepository( String id )
{
super( id );
- }
-
-
+ }
+
+
@Override
public void accept( IRepositoryVisitor visitor, int options )
{
- synchronized ( this )
+ List<ISigilProjectModel> models = SigilCore.getRoot().getProjects();
+ for ( ISigilProjectModel project : models )
{
- if ( bundles == null )
+ ISigilBundle b = project.getBundle();
+ if ( b == null )
{
- List<ISigilProjectModel> models = SigilCore.getRoot().getProjects();
- ArrayList<ISigilBundle> tmp = new ArrayList<ISigilBundle>( models.size() );
- for ( ISigilProjectModel n : models )
- {
- ISigilBundle b = n.getBundle();
- if ( b == null )
- {
- SigilCore.error( "No bundle found for project " + n.getProject().getName() );
- }
- else
- {
- tmp.add( b );
- }
+ SigilCore.error( "No bundle found for project " + project.getProject().getName() );
+ }
+ else
+ {
+ if ( (options & ResolutionConfig.COMPILE_TIME) != 0 ) {
+ b = compileTimeFilter(project, b);
}
- bundles = tmp.toArray( new ISigilBundle[tmp.size()] );
+ visitor.visit( b );
}
}
-
- for ( ISigilBundle b : bundles )
- {
- visitor.visit( b );
- }
}
+ private ISigilBundle compileTimeFilter(ISigilProjectModel project, ISigilBundle bundle)
+ {
+ bundle = (ISigilBundle) bundle.clone();
+
+ Collection<String> packages = findPackages(project);
+
+ for ( IPackageExport pe : bundle.getBundleInfo().getExports() ) {
+ final String packagePath = pe.getPackageName().replace('.', '/');
+ if ( !packages.contains(packagePath) ) {
+ bundle.getBundleInfo().removeExport(pe);
+ }
+ }
+
+ return bundle;
+ }
+
+
+
+ private Collection<String> findPackages(ISigilProjectModel project)
+ {
+ final IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
+ final IContentType javaContentType = contentTypeManager.getContentType("org.eclipse.jdt.core.javaSource");
+ final HashSet<String> packages = new HashSet<String>();
+
+ try
+ {
+ project.getProject().accept(new IResourceVisitor()
+ {
+ public boolean visit(IResource resource) throws CoreException
+ {
+ if ( resource instanceof IFile ) {
+ IFile f = (IFile) resource;
+ IContentType ct = contentTypeManager.findContentTypeFor(f.getName());
+ if ( ct != null && ct.isKindOf(javaContentType) ) {
+ IPath p = f.getProjectRelativePath();
+ p = p.removeLastSegments(1);
+ p = p.removeFirstSegments(1);
+ packages.add( p.toString() );
+ }
+ }
+
+ return true;
+ }
+ });
+ }
+ catch (CoreException e)
+ {
+ SigilCore.error( "Failed to read packages for " + project.getProject().getName() );
+ }
+
+ return packages;
+ }
+
+
+
public void refresh()
{
- synchronized ( this )
- {
- bundles = null;
- }
+ // no action
+ // TODO this method is used to prompt repository to update caches -
+ // however caches are complex to maintain in this workspace as the bundle is actively being developed...
+ // potential performance improvement in future?
}
-
- @Override
- protected void notifyChange()
- {
- refresh();
- super.notifyChange();
- }
-
-
public void resourceChanged( IResourceChangeEvent event )
{
try
{
- event.getDelta().accept( new IResourceDeltaVisitor()
- {
- public boolean visit( IResourceDelta delta ) throws CoreException
- {
- boolean result;
-
- IResource resource = delta.getResource();
- if ( resource instanceof IWorkspaceRoot )
- {
- result = true;
- }
- else if ( resource instanceof IProject )
- {
- IProject project = ( IProject ) resource;
- if ( SigilCore.isSigilProject( project ) )
- {
- switch ( delta.getKind() )
- {
- case IResourceDelta.CHANGED:
- if ( ( delta.getFlags() & UPDATE_MASK ) == 0 )
- {
- break;
- }
- // else
- // fall through on purpose
- case IResourceDelta.ADDED: // fall through on purpose
- case IResourceDelta.REMOVED: // fall through on purpose
- notifyChange();
- break;
- }
- result = true;
- }
- else
- {
- result = false;
- }
- }
- else if ( resource.getName().equals( SigilCore.SIGIL_PROJECT_FILE ) )
- {
- switch ( delta.getKind() )
- {
- case IResourceDelta.CHANGED:
- case IResourceDelta.ADDED:
- case IResourceDelta.REMOVED:
- notifyChange();
- }
- result = false;
- }
- else
- {
- result = false;
- }
- return result;
- }
- } );
+ switch (event.getType()) {
+ case IResourceChangeEvent.PRE_REFRESH:
+ handleRefresh(event);
+ break;
+ case IResourceChangeEvent.POST_CHANGE:
+ handleChange(event);
+ break;
+ }
}
catch ( CoreException e )
{
@@ -166,4 +161,71 @@
}
}
+
+ private void handleRefresh(IResourceChangeEvent event)
+ {
+ SigilCore.log("Refreshing workspace repository");
+ notifyChange();
+ }
+
+
+ private void handleChange(IResourceChangeEvent event) throws CoreException
+ {
+ event.getDelta().accept( new IResourceDeltaVisitor()
+ {
+ public boolean visit( IResourceDelta delta ) throws CoreException
+ {
+ boolean result;
+
+ IResource resource = delta.getResource();
+ if ( resource instanceof IWorkspaceRoot )
+ {
+ result = true;
+ }
+ else if ( resource instanceof IProject )
+ {
+ IProject project = ( IProject ) resource;
+ if ( SigilCore.isSigilProject( project ) )
+ {
+ switch ( delta.getKind() )
+ {
+ case IResourceDelta.CHANGED:
+ if ( ( delta.getFlags() & UPDATE_MASK ) == 0 )
+ {
+ break;
+ }
+ // else
+ // fall through on purpose
+ case IResourceDelta.ADDED: // fall through on purpose
+ case IResourceDelta.REMOVED: // fall through on purpose
+ notifyChange();
+ break;
+ }
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+ }
+ else if ( resource.getName().equals( SigilCore.SIGIL_PROJECT_FILE ) )
+ {
+ switch ( delta.getKind() )
+ {
+ case IResourceDelta.CHANGED:
+ case IResourceDelta.ADDED:
+ case IResourceDelta.REMOVED:
+ notifyChange();
+ }
+ result = false;
+ }
+ else
+ {
+ result = false;
+ }
+ return result;
+ }
+ } );
+ }
+
}
diff --git a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepositoryProvider.java b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepositoryProvider.java
index d03bef4..140fe5a 100644
--- a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepositoryProvider.java
+++ b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/repository/eclipse/WorkspaceRepositoryProvider.java
@@ -44,7 +44,7 @@
if ( repository == null )
{
repository = new WorkspaceRepository( id );
- ResourcesPlugin.getWorkspace().addResourceChangeListener( repository, IResourceChangeEvent.POST_CHANGE );
+ ResourcesPlugin.getWorkspace().addResourceChangeListener( repository, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_REFRESH );
}
return repository;
}
diff --git a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/util/JavaHelper.java b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/util/JavaHelper.java
index 86ca1e9..23b4a73 100644
--- a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/util/JavaHelper.java
+++ b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/util/JavaHelper.java
@@ -363,7 +363,7 @@
ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
ResolutionConfig config = new ResolutionConfig( ResolutionConfig.INCLUDE_OPTIONAL
- | ResolutionConfig.IGNORE_ERRORS | ResolutionConfig.INDEXED_ONLY | ResolutionConfig.LOCAL_ONLY );
+ | ResolutionConfig.IGNORE_ERRORS | ResolutionConfig.INDEXED_ONLY | ResolutionConfig.LOCAL_ONLY | ResolutionConfig.COMPILE_TIME );
IResolution resolution;
try
@@ -410,6 +410,7 @@
Set<ISigilBundle> all, List<IModelElement> requirements, IProgressMonitor monitor ) throws CoreException
{
IAccessRule[] rules = buildAccessRules( project, provider, all, requirements );
+ IClasspathAttribute[] attrs = new IClasspathAttribute[0];
ISigilProjectModel other = provider.getAncestor( ISigilProjectModel.class );
@@ -418,11 +419,11 @@
if ( other == null )
{
provider.synchronize( monitor );
- return newBundleEntry( provider, rules, null, false );
+ return newBundleEntry( provider, rules, attrs, false );
}
else
{
- return newProjectEntry( other, rules, null, false );
+ return newProjectEntry( other, rules, attrs, false );
}
}
catch ( IOException e )
@@ -432,62 +433,9 @@
}
- private static IAccessRule[] buildExportRules( ISigilBundle bundle, Set<ISigilBundle> all,
- List<IModelElement> requirements )
- {
- Set<IPackageExport> ex = mergeExports( bundle, all, requirements );
-
- IAccessRule[] rules = new IAccessRule[ex.size() + 1];
-
- Iterator<IPackageExport> iter = ex.iterator();
- for ( int i = 0; i < rules.length - 1; i++ )
- {
- IPackageExport p = iter.next();
- rules[i] = JavaCore.newAccessRule( new Path( p.getPackageName().replace( '.', '/' ) ).append( "*" ),
- IAccessRule.K_ACCESSIBLE );
- }
-
- rules[rules.length - 1] = DENY_RULE;
-
- return rules;
- }
-
-
- private static Set<IPackageExport> mergeExports( ISigilBundle bundle, Set<ISigilBundle> all,
- List<IModelElement> requirements )
- {
- IBundleModelElement headers = bundle.getBundleInfo();
- // FIXME treeset as PackageExport does not implement equals/hashCode
- TreeSet<IPackageExport> exports = new TreeSet<IPackageExport>( headers.getExports() );
- IRequiredBundle host = headers.getFragmentHost();
- if ( host != null )
- {
- for ( ISigilBundle b : all )
- {
- if ( host.accepts( b.getBundleInfo() ) )
- {
- exports.addAll( b.getBundleInfo().getExports() );
- break;
- }
- }
- }
- return exports;
- }
-
-
private static Collection<IClasspathEntry> newProjectEntry( ISigilProjectModel n, IAccessRule[] rules,
IClasspathAttribute[] attributes, boolean export ) throws CoreException
{
- // if (rules == null) {
- // rules = JavaHelper.buildExportRules(n.getBundle());
- // }
-
- if ( attributes == null )
- {
- attributes = new IClasspathAttribute[]
- {};
- }
-
ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>();
entries.add( JavaCore.newProjectEntry( n.getProject().getFullPath(), rules, false, attributes, export ) );
for ( IClasspathEntry e : n.getJavaModel().getRawClasspath() )
@@ -518,16 +466,6 @@
{
String name = bundle.getBundleInfo().getSymbolicName();
- // if (rules == null) {
- // rules = JavaHelper.buildExportRules(bundle);
- // }
-
- if ( attributes == null )
- {
- attributes = new IClasspathAttribute[]
- {};
- }
-
if ( bundle.getBundleInfo().getVersion() != null )
{
name += "_version_" + bundle.getBundleInfo().getVersion();
@@ -547,7 +485,7 @@
if ( path == null )
{
- SigilCore.error( "Found null path for " + bundle.getBundleInfo().getSymbolicName() );
+ SigilCore.error( "Found null path for " + bundle.getSymbolicName() );
entries = Collections.emptyList();
}
else
@@ -820,6 +758,48 @@
return rules.toArray( new IAccessRule[rules.size()] );
}
+
+ private static IAccessRule[] buildExportRules( ISigilBundle bundle, Set<ISigilBundle> all,
+ List<IModelElement> requirements )
+ {
+ Set<IPackageExport> ex = mergeExports( bundle, all, requirements );
+
+ IAccessRule[] rules = new IAccessRule[ex.size() + 1];
+
+ Iterator<IPackageExport> iter = ex.iterator();
+ for ( int i = 0; i < rules.length - 1; i++ )
+ {
+ IPackageExport p = iter.next();
+ rules[i] = JavaCore.newAccessRule( new Path( p.getPackageName().replace( '.', '/' ) ).append( "*" ),
+ IAccessRule.K_ACCESSIBLE );
+ }
+
+ rules[rules.length - 1] = DENY_RULE;
+
+ return rules;
+ }
+
+
+ private static Set<IPackageExport> mergeExports( ISigilBundle bundle, Set<ISigilBundle> all,
+ List<IModelElement> requirements )
+ {
+ IBundleModelElement headers = bundle.getBundleInfo();
+ // FIXME treeset as PackageExport does not implement equals/hashCode
+ TreeSet<IPackageExport> exports = new TreeSet<IPackageExport>( headers.getExports() );
+ IRequiredBundle host = headers.getFragmentHost();
+ if ( host != null )
+ {
+ for ( ISigilBundle b : all )
+ {
+ if ( host.accepts( b.getBundleInfo() ) )
+ {
+ exports.addAll( b.getBundleInfo().getExports() );
+ break;
+ }
+ }
+ }
+ return exports;
+ }
/*