Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 325172

Summary: Facet framework does not respect conflicts if one facet is undefined
Product: [WebTools] WTP Common Tools Reporter: Zina Mostafia <zina>
Component: Faceted Project FrameworkAssignee: Konstantin Komissarchik <konstantin>
Status: RESOLVED WONTFIX QA Contact: Konstantin Komissarchik <konstantin>
Severity: enhancement    
Priority: P3 CC: bjustin, yurykats
Version: 3.2.2   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Zina Mostafia CLA 2010-09-13 17:43:26 EDT
In my facet definition, I am specifying some facets that are conflicting with mine.
Some of these facets are optional.
This is an example

<project-facet-version facet="my.facet" version="1.0">
  <action type="install" id="my.facet.install">
   <delegate class="project.facet.MyFacetInstallDelegate"/>
   <config-factory class="project.facet.MyFacetInstallDataModelProvider"/>
  </action>
 <constraint>
  <and>
   <requires facet="java" version="[1.5"/>
   <conflicts facet="jst.ejb"/>   <---------------This is defined
   <conflicts facet="my.conflicting.facet"/>  <--------This is Not defined
  </and>
 </constraint>
</project-facet-version>

In the example above, there is no facet defined named "my.conflicting.facet".

What I see is that all of the conflicting facets show up in the project facet properties page, and the framework just ignores to filter the rest of the facet, in this case the "jst.ejb".

There is nothing in the .log file that tells me about an exception. I will see an error message in the log that tells me that "my.conflicting.facet" is  undefined. And that whole section is being ignored by the framework.

If I add ignore-problems="facet-not-defined", I will not see the error message in the log but would not solve the problem.
Comment 1 Zina Mostafia CLA 2010-09-13 18:00:43 EDT
Raising as a hotbug.
Affiliation : IBM
Release : 3.2.2
Justification : prevents using the facet framework to define conflicting facets in the environment where multiple optionally installed components might not work together.
Comment 2 Konstantin Komissarchik CLA 2010-09-13 18:56:18 EDT
The behavior your are seeing is by design.

When a subexpr references entities that cannot be resolved, the system needs to determine how much of the expression tree to prune out as invalid. The current behavior is to prune until the nearest OR. The ignore-problems directive doesn't affect pruning behavior. It only affects logging of problems.

We can argue about what is proper for pruning behavior, but changing the pruning algorithm would be an API-changing act and more importantly no change is necessary to make this scenario work...

The trick is to use groups. Groups are specifically provided as a way for your facet to reference 0 or more facets in a constraint without referencing each one separately. 

Here is your scenario expressed using groups. I have verified that this works as expected.

<extension point="org.eclipse.wst.common.project.facet.core.facets">
  <project-facet id="ReproBug325172"/>
  <project-facet-version facet="ReproBug325172" version="1.0">
    <constraint>
      <and>
        <requires facet="java" version="[1.5"/>
        <conflicts group="my.custom.group"/>
      </and>
    </constraint>
  </project-facet-version>
</extension>
  
<extension point="org.eclipse.wst.common.project.facet.core.groups">
  <members group="my.custom.group">
    <include facet="jst.ejb"/>
    <include facet="my.conflicting.facet"/>
  </members>
</extension>

I am removing hotbug_request as there is a solution using existing means. I am also downgrading severity to an enhancement as that's the level to have any discussion over the behavior of the pruning algorithm. I am also closing this bug as WONTFIX (at least for now). Note that I am not fundamentally opposed to having a discussion about the pruning algorithm, but it looks like this particular scenario already has a solution and there isn't much to be gained from changing the pruning algorithm.
Comment 3 Zina Mostafia CLA 2010-09-14 12:35:48 EDT
I used the workaround provided and it resolved the issue. 
With two important limitations:
1) I cannot specify a version for the facet that I include in the group.
2) For facets that are not defined, I get an error in the .log
!MESSAGE Project facet my.bad.facet has not been defined. It is used in plugin my.plugin.

The reason is that I cannot specify the 
1)version attribute or
2)ignore-problems="facet-not-defined" attribute

So although with this workaround, I agree it is not a hotbug anymore, but I would like to keep this defect open, to probably add these two attributes to the group.
Comment 4 Konstantin Komissarchik CLA 2010-09-14 13:47:17 EDT
The groups extension point has ability to specify versions. Take a look at the extension point schema. 

The groups extension point also works in aggregating fashion. This allows you to place the contribution that references a particular facet in the context where that facet is available.

This could be in one plugin:

<extension point="org.eclipse.wst.common.project.facet.core.groups">
  <members group="my.custom.group">
    <include facet="jst.ejb"/>
  </members>
</extension>

This could be in another:

<extension point="org.eclipse.wst.common.project.facet.core.groups">
  <members group="my.custom.group">
    <include facet="my.conflicting.facet"/>
  </members>
</extension>

The result is a group of two facets. Modularity is usually the best way to solve undefined references problem. If you still think you have a usecase for ignore-problems switch on the groups extension point, please open that a separate enhancement request. Make sure to describe why modularity doesn't work for you scenario.
Comment 5 Justin Berstler CLA 2010-09-27 17:53:50 EDT
(In reply to comment #4)
> The groups extension point also works in aggregating fashion. This allows you
> to place the contribution that references a particular facet in the context
> where that facet is available.


The problem is that no "context where the facet is available" may exist that is under my control to change.  

For example, if in some product that builds on top of Eclipse I define Facet X.  I happen to know that my facet conflicts with Facet Y, which is provided by a third party vendor.  I have no control over whether or not my user has installed the plugins which define Facet Y, but what I do know is that my Facet X cannot work with their Facet Y.  Under the current implementation, I cannot take the most natural course of action which is to define a conflict between these two facets, regardless of whether Facet Y is defined.  What you are suggesting then, is that it is the third party who defines Facet Y who is responsible to add their facet to my conflicting group when, in reality, that vendor doesn't (and shouldn't have to) know or care about my facet at all.
Comment 6 Konstantin Komissarchik CLA 2010-09-27 18:07:08 EDT
> The problem is that no "context where the facet is available" may exist that is
> under my control to change.  

You can create such a context. Given component A and component B which don't otherwise depend on each other, you can create component C which depends on both and handles their integration. In Eclipse/OSGi realm, this would be handled with an optional bundle as part of your product. 

Also see...

> If you still think you have a usecase for ignore-problems switch on the groups 
> extension point, please open that a separate enhancement request. Make sure to 
> describe why modularity doesn't work for you scenario.