Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SkinnyWar Support issue #27

Open
mattcolegate opened this issue Aug 30, 2023 · 14 comments
Open

SkinnyWar Support issue #27

mattcolegate opened this issue Aug 30, 2023 · 14 comments

Comments

@mattcolegate
Copy link

Hi, I'm a developer for Websphere Developer Tools. We have a customer who is using true in his EAR's POM.xml and it's not importing properly when we pull it into our Eclipse environment using m2e-wtp.

There are sample projects available for recreation purposes from our customer at https://github.com/marioja/sample-tests. There are prereq setup details at https://github.com/marioja/sample-tests/tree/LOOSECONFIG_CLASSPATH_ISSUE/simple-jee, and the main problems are detailed at https://github.com/marioja/sample-tests/tree/SKINNY-FAILS/simple-jee and https://github.com/marioja/sample-tests/tree/SKINNY-WORKS/simple-jee.

By default, it assumes that the shared libraries are being deployed in the WAR and we would like them to point to the libraries in the EAR.

We think that some of the changes are likely to start in the org.eclipse.m2e.wtp.EarPluginConfiguration package but would appreciate being shown round!

@cbridgha
Copy link

cbridgha commented Sep 5, 2023

Hi @fbricon hope you are doing well. Matt's group above is looking at the source to investigate a patch for this functionality. We know this project doesn't release too often, but any assistance if/when a PR is possible would be welcome. Obviously any proposed change will be sent to you for review.

Thanks! - Chuck

@laeubi
Copy link
Member

laeubi commented Sep 6, 2023

@cbridgha a PR is always welcome, m2e has no "freeze" period or similar and you can always use the snapshot repository until a new release is made (usually we do at least one per eclipse release sometimes even more often).

If there are customer demands a good way for speeding things up is offering a sponsoring for those working on their free time on this project (or of course working on the issue directly).

@fbricon
Copy link
Contributor

fbricon commented Sep 6, 2023

@mattcolegate @cbridgha there are 2 ways to implement a solution, the right one and the wrong one (a.k.a the hacky one).

  • the right one: modify WTP so EAR components can be configured to filter out war dependencies (from both workspace projects and war archives). Once that's done, you then would have to make https://github.com/eclipse-m2e/m2e-wtp/blob/master/org.eclipse.m2e.wtp/src/org/eclipse/m2e/wtp/EarProjectConfiguratorDelegate.java configure WTP's EAR component, based on the maven configuration read from EarPluginConfiguration.

  • the wrong one : (doesn't require changing WTP) If EarPluginConfiguration says skinny war, have EarProjectConfiguratorDelegate loop through each of its Web projects dependencies. For each of them remove the DEPENDENCY_ATTRIBUTE on each classpath entry of the Maven container, that matches a dependency of the EAR project. Then for all archive .war dependencies, recreate a skinny war on disk, if necessary, or use a cached version, then add it to the EAR deployment configuration, instead of the .war from the local .m2 repo.
    Additionally, in the WebProjectConfiguratorDelegate, search for all skinny war-enabled EAR projects in the workspace. If the current web project under configuration belongs to one of those EARs, then don't set the DEPENDENCY_ATTRIBUTE to classpath entries that are also configured as EAR dependecies.

Reasons why the wrong approach is wrong:

  • you're configuring the same web projects twice, in EarProjectConfiguratorDelegate and WebProjectConfiguratorDelegate, because you have a chicken/egg problem (which ear or web project was configured first)
  • if a web project belongs to both a skinny-war enabled EAR and a regular EAR, you're screwed. As it can't be both regular and skinny at the same time.
  • if a web project belongs to different skinny-war enabled EARs with different dependency sets, you're screwed, since you could have a dependency embedded in WEB-INF/lib for one EAR, not for the other

@fbricon
Copy link
Contributor

fbricon commented Sep 6, 2023

I forgot to mention you need to rewrite the MANIFEST.MF of the web projects and .war archives as well

@pnickoll
Copy link
Contributor

pnickoll commented Sep 6, 2023

Hi, I have a couple of questions on that:

  1. " configure WTP's EAR component" Do you mean we should write to a config file (the .component file) a new setting which can be read by WTP code and actioned? Or do you mean m2e-wtp can invoke new code on WTP - for example changing

    IVirtualComponent depComponent = ComponentCore.createComponent(project);
    to invoke a new overriden version of ComponentCore.createComponent where we pass in a flag to say filter out war dependencies?

  2. You mentioned changing MANIFEST.MF in the web project. I believe this is generated by m2e-wtp (target/m2e-wtp/web-resources/META-INF/manifest.mf) during import. By changing this would it mean that exporting the war file (NOT inside an ear file, just exporting a WAR) would also not include the jars? Would that break WAR files?

@pnickoll
Copy link
Contributor

pnickoll commented Sep 7, 2023

@fbricon Hi would you be able to take a peek at my above questions?

@fbricon
Copy link
Contributor

fbricon commented Sep 7, 2023

Hi, I have a couple of questions on that:

  1. " configure WTP's EAR component" Do you mean we should write to a config file (the .component file) a new setting which can be read by WTP code and actioned? Or do you mean m2e-wtp can invoke new code on WTP - for example changing
    IVirtualComponent depComponent = ComponentCore.createComponent(project);

    to invoke a new overriden version of ComponentCore.createComponent where we pass in a flag to say filter out war dependencies?

I would probably set a skinnyWars=true metadata in the EAR's IVirtualComponent, from EarProjectConfigurator, then expect whatever WTP deployment implementation that handles Ear components to do exactly what the Maven Ear plugin does: strip war (projects/archives) from dependencies already in the EAR, rewrite manifests before actual deployment

  1. You mentioned changing MANIFEST.MF in the web project. I believe this is generated by m2e-wtp (target/m2e-wtp/web-resources/META-INF/manifest.mf) during import. By changing this would it mean that exporting the war file (NOT inside an ear file, just exporting a WAR) would also not include the jars? Would that break WAR files?

Yeah if you take the wrong route, then you can forget about single war deployment or exporting as war, since the manifest would be covering skinny war enabled EARs only

On a side note, anyone manually exporting a maven war project using Eclipse buttons is doing it wrong. In Maven world, "mvn package" is the one and only truth

@fbricon
Copy link
Contributor

fbricon commented Sep 7, 2023

I think there might be a 3rd way to get skinny war support working, without having to change WTP, and without screwing single wars, or wars in multiple EARs.

Basically, you would create a new custom IVirtualComponent, let's call it SkinnyWarVirtualComponent, akin to the IOverlayVirtualComponent I made to handle war overlays. Then, a custom reference resolver would be able to do all the skinny war magic (exclude jars, rewrite custom manifest), a bit like OverlayReferenceResolver

Basically, EarProjectConfigurator would do something similar to what OverlayConfigurator does, and create SkinnyWarVirtualComponent for every web project dependency it finds in

if(workspaceDependency != null && !workspaceDependency.getProject().equals(project)
&& workspaceDependency.getFullPath(artifact.getFile()) != null) {
//artifact dependency is a workspace project
IProject depProject = preConfigureDependencyProject(workspaceDependency, monitor);
if (ModuleCoreNature.isFlexibleProject(depProject)) {
depComponent = createDependencyComponent(earComponent, depProject);
}
} else {
//artifact dependency should be added as a JEE module, referenced with M2_REPO variable
depComponent = createDependencyComponent(earComponent, earModule.getArtifact());
}

@fbricon
Copy link
Contributor

fbricon commented Sep 7, 2023

Similar to the Overlay virtual component, a new skinny war component (+resolver) would need no reference to Maven/m2e at all (that's why it's in a separate plugin)

@fbricon
Copy link
Contributor

fbricon commented Sep 7, 2023

Tests for Overlays, as a reference, exist in the separate m2e-wtp-tests repo : https://github.com/jbosstools/m2e-wtp-tests/blob/master/org.eclipse.m2e.wtp.tests/src/org/eclipse/m2e/wtp/tests/OverlayTest.java

@pnickoll
Copy link
Contributor

pnickoll commented Sep 7, 2023

Thanks @fbricon I will go and dig deeper into option 3, it sounds promising but I need to get my head around it

@pnickoll
Copy link
Contributor

Hi @fbricon I've taken a peek at it today (I've been away for a week). I think I have a bit of understanding.

I assume we'd need to register an extension point in Eclipse for the SkinnyWarResolver (in the plugin.xml)?

Were you suggesting that EarProjectConfiguratorDelegate should create another component for each web project on top of the components it already creates (J2EEModuleVirtualComponent)?

I tried getting EarProjectConfiguratorDelegate to create a new SkinnyWarCompopnent as well as the existing one (and saw it did update the .component file to create 2 entries) but my resolver was not invoked, presumably as my component was a very basic class extending org.eclipse.wst.common.componentcore.internal.resources.VirtualComponent and another resolver was able to resolve it.

If using just the new component to replace the existing depComponent I was wondering if the new Resolver could first delegate to the existing resolver (I've not found out which one that is yet) and then modify the results?

@fbricon
Copy link
Contributor

fbricon commented Sep 19, 2023

First of all, given maven-ear-plugin 3.2.0 expanded the concept of skinny wars to other modules, from now on we should speak about skinny modules.

So yes you'd have a resolver like

<plugin>
     <extension
         point="org.eclipse.wst.common.modulecore.referenceResolver">
      <resolver
            class="org.eclipse.m2e.wtp.skinnymodules.modulecore.SkinnyModuleReferenceResolver"
            id="org.eclipse.m2e.wtp.skinnymodules.modulecore.SkinnyModuleReferenceResolver">
      </resolver>
   </extension>
</plugin>

and in EarProjectConfiguratorDelegate, when iterating over Ear modules:

  • if skinnyModules=true, then all matching projects/binaries would be turned into skinny module components
  • else if skinnyWars=true, only Web Projects/.war would be turned into skinny module components
  • else create regular components

So you want 1 component entry only per artifact.

I don't think delegating to regular resolver applies here. But for sure the Skinny components should generate something very close to the regular components (minus some jars + manifest rewrite)

@marioja
Copy link

marioja commented Jan 8, 2024

Hi, I cannot say for certain that I understood everything that was said since I do not know much about the design and the internals of how m2e works. I do know a lot more about skinny wars (or as @fbricon said correctly skinny modules). I wanted to note something that may have been forgotten when building skinny modules.

Currently, when maven builds a multi-module project that contains a skinny WAR, when the WAR module is built there is no impact, i.e. the WAR module is built as a fat module with all the required dependencies in WEB-INF/lib and no MANIFEST references in the class-path entry. This is how it should always work as the WAR should be deployable on its own to an application server (i.e. tomcat) or a JEE container. The skinny module should only have an effect when it is packaged inside an EAR module. This is how maven currently does it and this is how M2E should also reflect it. This means that the EAR always needs to reference a skinnied module, not the fat module that the maven build would create. I apologize if I stated the obvious but to me it appeared that this was not reflected in some of the prior comments.

If someone was willing to guide me I would be willing to help in fixing this issue. You can contact me if interested

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants